Nginx 通过 try_files 实现图片水印按需生成:先查缓存文件,未命中则内部重写至后端脚本生成并落盘。配置使用 alias 定向缓存目录,配合 location 和 @named 阻止直接访问,后端需解析路径、加水印、保存并输出,注意安全过滤与权限设置。

利用 Nginx 的 try_files 指令实现图片水印的实时按需生成,核心思路是:当用户请求一张带水印的图片(如 /w/100x80/logo.png)时,Nginx 先尝试查找已缓存的水印图;若不存在,则将请求内部重写到一个动态处理脚本(如 PHP、Python 或 Go 服务),由后端生成并返回水印图,同时可自动落盘供下次直接命中。
水印 URL 设计与路径映射
约定水印资源统一放在 /w/ 路径下,格式为:/w/{width}x{height}/{filename}(例如 /w/200x150/photo.jpg)
该路径不对应真实文件,而是作为“虚拟水印接口”。Nginx 需将这类请求按优先级依次检查:
- 是否存在已生成的水印图(如
/data/watermarked/200x150/photo.jpg) - 若不存在,内部重写到水印生成服务(如
/watermark.php),并透传原始参数
nginx 配置中的 try_files 写法
在 server 块中添加 location 匹配规则:
location ^~ /w/ {
# 解析 width x height 和原始文件名
rewrite ^/w/(\d+x\d+)/(.+)$ /watermark.php?size=$1&src=$2 break;
<pre class="brush:php;toolbar:false;"># 尝试命中本地缓存文件(推荐放在 fastcgi_cache 或独立静态目录)
# 这里假设缓存根目录为 /data/watermarked/
root /data;
# try_files $uri 尝试访问 /data/w/200x150/photo.jpg(无意义,跳过)
# 改用 alias + try_files 组合更合理:
}
更实用的做法是用 alias 定向缓存目录,并用 try_files 查找实际文件:
location ^~ /w/ {
alias /data/watermarked/;
<pre class="brush:php;toolbar:false;"># $uri 是 /w/200x150/photo.jpg → alias 后变为 /data/watermarked/200x150/photo.jpg
try_files $uri @watermark;
}
location @watermark {
内部重写到生成脚本,携带原始 URI 信息
rewrite ^/w/(.+)$ /watermark.php?path=$1 last;
}
后端水印脚本的关键逻辑(以 PHP 为例)
/watermark.php 需完成三件事:解析参数、生成水印图、输出并缓存到对应路径:
- 从
$_GET['path']提取200x150/photo.jpg,拆出尺寸和源图名 - 根据尺寸和文件名,确定源图真实路径(如映射到
/data/original/photo.jpg) - 用 GD 或 Imagick 添加文字/图片水印,保存到
/data/watermarked/200x150/photo.jpg - 设置合适的 Content-Type(如
image/jpeg)和缓存头(Cache-Control: public, max-age=86400) - 输出二进制图像内容(不要 echo 其他字符)
注意事项与优化点
避免常见陷阱:
-
try_files中不能直接使用变量拼接路径(如$document_root/watermarked/$uri),应靠alias或root配合 URI 结构对齐 - 确保
/data/watermarked/目录有写权限,且 PHP 进程可读源图目录 - 首次生成较慢,建议配合 Nginx 的
proxy_cache或 FastCGI 缓存,减少重复调用后端 - 对恶意构造的
path参数(如../../../etc/passwd)必须严格过滤,只允许数字、字母、点、斜杠、x
这种方式无需额外代理层,纯靠 Nginx 路由 + 脚本协作,轻量、可控、易于部署。水印图一旦生成即静态化,后续请求零计算开销。










