Nginx中配置静态资源Content-Disposition需通过location精确匹配后缀,设default_type为application/octet-stream并用add_header设置attachment及filename,避免if嵌套、跨域拦截和HTTP头注入风险。

在 Nginx 中配置静态资源的 Content-Disposition,核心是**通过 location 精确匹配文件类型,显式控制响应头与 MIME 类型**,而不是依赖全局或模糊设置。直接用 add_header 在 server 或 http 块里加,往往无效或出错——因为它是“追加”行为,且无法条件触发,容易和后端、自动推断的 Content-Type 冲突。
按文件后缀强制下载(推荐)
适用于 PDF、ZIP、EXE、XLSX 等希望用户保存而非预览的资源:
- 用正则
location ~* \.(pdf|zip|exe|xlsx|docx|rar)$精确捕获请求 - 设
default_type application/octet-stream:关闭 Nginx 自动猜类型(避免返回application/pdf导致浏览器内嵌) - 用
add_header Content-Disposition "attachment; filename=$request_filename":保留原始文件名(注意 URL 编码需前端处理,$request_filename 是解码后的安全路径) - 可选加
add_header Cache-Control "no-store"防止缓存干扰下载逻辑
按参数动态切换 inline / attachment
当同一类文件(如 PDF)有时要预览、有时要下载,可通过 URL 参数控制:
- 匹配带
?inline=1的请求:location ~* \.pdf$ { if ($args ~ inline=1) { add_header Content-Disposition "inline"; } } - 但注意:
if在 location 中有局限,更稳妥的做法是拆成两个 location: -
location ~* /inline/.*\.pdf$ { add_header Content-Disposition "inline"; }(前端请求改用 /inline/report.pdf) - 或配合
map指令提前定义变量,在后续 add_header 中引用
确保前端能读到该响应头(尤其跨域/iframe 场景)
如果前端用 Axios、fetch 下载时需要解析 Content-Disposition 中的文件名,但拿不到这个 header,大概率是被浏览器跨域策略拦截了:
- 必须显式暴露:
add_header Access-Control-Expose-Headers "Content-Disposition"; - 该指令需放在 proxy_pass 所在的 location 块中,且要和
Access-Control-Allow-Origin等 CORS 头共存 - 若使用
internal或X-Accel-Redirect,也要确保这些内部重定向不丢弃已设置的 header
安全提醒:filename 不要拼接不可信输入
不要写 filename=$arg_name 或 filename=$uri —— 攻击者可能构造 /download?name=test%22%3E%3Cscript%3Ealert(1)%3C/script%3E.pdf,导致 HTTP 头注入。可靠做法是:
- 用
$request_filename(服务端真实路径,不含用户可控字符) - 或提取纯净文件名:
location ~* ^/files/(?<fname>[^/]+?\.(pdf|zip))$ { add_header Content-Disposition "attachment; filename=$fname"; }</fname> - 对中文名,优先用
filename*=UTF-8''...格式,但需确保 Nginx 版本 ≥ 1.17.6 且启用charset utf-8


















