nginx防盗链与cors共存时常见故障源于执行顺序与响应头覆盖,需重点排查options预检被拒、cors头未生效或被覆盖、静态与动态资源配置混用三大问题。

当 Nginx 同时配置防盗链(valid_referers)和跨域(CORS)响应头时,常见故障不是“两者互斥”,而是规则执行顺序与响应头覆盖导致浏览器行为异常——比如图片/字体加载失败、预检请求被 403 拦截、或 CORS 头缺失。排查需聚焦三点:防盗链是否误拒 OPTIONS 请求、CORS 头是否被 location 继承或覆盖、以及响应头是否因条件判断被跳过。
确认防盗链是否拦截了 OPTIONS 预检请求
防盗链规则默认作用于所有请求方法,包括浏览器自动发起的 OPTIONS 预检。若 valid_referers 未显式允许空 Referer 或特定来源,OPTIONS 请求会直接返回 403,导致跨域失败,且 CORS 头根本不会发出。
- 检查 location 块中是否对
OPTIONS方法做了例外处理,例如:if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin 'https://trusted.com'; add_header Access-Control-Allow-Methods 'GET, OPTIONS'; add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With'; add_header Access-Control-Max-Age 86400; add_header Content-Length 0; return 204; } - 确保
valid_referers包含none(允许空 Referer),因为预检请求通常不带 Referer:valid_referers none server_names *.trusted.com; - 用 curl 模拟预检请求验证:
curl -I -X OPTIONS -H "Origin: https://trusted.com" -H "Access-Control-Request-Method: GET" https://your-domain.com/font.woff2,观察是否返回 403 或缺少 CORS 头
检查 CORS 头是否被防盗链 location 覆盖或未生效
CORS 头必须在最终匹配的 location 块中添加,且需用 always 参数确保即使返回 403/404 也携带(但实际应避免在拒绝响应中发 CORS 头)。若防盗链配置在父 location,而 CORS 头只写在子 location(如正则匹配静态后缀),可能因匹配优先级问题失效。
- 把 CORS 头放在与
valid_referers相同的 location 块内,避免嵌套或继承冲突 - 所有
add_header必须加always,否则 Nginx 默认只在 2xx/3xx 响应中添加:add_header Access-Control-Allow-Origin 'https://trusted.com' always; - 避免在 http/server 全局块写 CORS 头,防止污染非静态资源路径;优先限定到具体静态资源 location,例如:
location ~* \.(js|css|woff2|ttf|png|jpg|gif)$ { valid_referers none server_names *.trusted.com; add_header ... always; }
验证响应头是否真实返回且无重复/冲突
Nginx 不允许多次设置同一响应头(除非用 always),而防盗链模块或 proxy_pass 场景下可能引入额外头信息,造成 CORS 头被覆盖或浏览器拒绝(如同时出现 Access-Control-Allow-Origin: * 和 Access-Control-Allow-Credentials: true)。
- 用 curl 精确测试目标资源,带上 Origin 头:
curl -I -H "Origin: https://trusted.com" https://your-domain.com/main.css,确认返回中包含完整 CORS 头,且无重复 - 检查是否意外启用了
Access-Control-Allow-Credentials true;若用了通配符*作为 Origin,必须删除该行,否则浏览器直接拒绝 - 若使用了
proxy_pass(如反向代理 API),确保后端未重复添加 CORS 头,Nginx 层应统一控制,避免头冲突
区分静态资源与动态接口的配置边界
防盗链主要针对静态文件(图片、字体、JS/CSS),而 CORS 对 API 接口要求不同(常需 Credentials、更多 Methods)。混用同一 location 容易逻辑错乱。
- 为静态资源单独设 location(如
location /static/或后缀匹配),专注防盗链 + 简单 CORS(仅 GET/OPTIONS,无 Credentials) - 为 API 接口另设 location(如
location /api/),关闭防盗链,按需配置完整 CORS(支持 POST/PUT,可启用 Credentials) - 字体文件(.woff2/.ttf)特别敏感:即使防盗链放行,缺少
Access-Control-Allow-Origin仍会报错,务必确保该头存在且值明确











