Nginx配置Content-Disposition下载头时文件缺失.json后缀问题排查
配置错误原因
原配置存在两个核心问题导致文件名后缀不生效:
- 变量解析语法错误:Nginx 仅对双引号包裹的字符串做变量插值,单引号内的内容会以纯字面量形式原样输出。原配置中
set $fname '${id}.json';使用单引号,${id}不会被替换为实际的UUID值,最终响应头里的文件名参数是无效的${id}.json,大部分浏览器遇到这种非法文件名会直接忽略该参数,取请求路径最后一段(即纯UUID)作为保存的文件名,因此看不到.json后缀。另外Nginx原生变量引用不需要使用Shell风格的${}花括号包裹,直接写$变量名即可。 - 响应头冲突未处理:默认
add_header指令属于「追加头」逻辑,不会覆盖后端服务原接口返回的同名Content-Disposition头;同时默认规则下add_header仅对2xx、3xx类常规状态码生效,其他状态码下不会追加自定义头。如果原后端接口本身返回了不带.json后缀的Content-Disposition头,自定义的头会被浏览器忽略。
另外原配置的rewrite逻辑存在冗余,rewrite自身的正则捕获组还可能覆盖location正则的捕获值,提升异常概率。
修正方案
直接简化配置,去掉冗余的rewrite和中间变量,先隐藏后端返回的冲突响应头,再强制追加自定义下载头即可,修正后的配置如下:
location ~ "^/download/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" { # 先隐藏后端可能返回的Content-Disposition头,避免头冲突 proxy_hide_header Content-Disposition; # 强制添加下载头,用双引号保证$1被解析为捕获到的UUID,加always参数确保所有状态码下都生效 add_header Content-Disposition "attachment; filename=\"$1.json\"" always; # 直接拼接转发路径,不需要额外rewrite,将捕获到的UUID拼到/api/路径后转发给后端 proxy_pass http://localhost:8081/api/$1; }
配置生效逻辑说明:
- 正则匹配/download/后面的合法UUID,捕获到的UUID值直接存到
$1变量中 - 转发时直接请求后端
/api/{UUID}接口,和原接口返回的响应内容完全一致 - 强制覆盖下载响应头,告诉浏览器将响应内容以
{UUID}.json为文件名保存,不会出现后缀丢失问题
内容的提问来源于stack exchange,提问作者George Livanoss
相关产品推荐
相关产品推荐

