一、问题/场景描述
在现代前后端分离的Web应用中,跨域资源共享(CORS)是常见需求。然而,浏览器在发送某些跨域请求前,会先发送一个OPTIONS方法的预检请求(Preflight Request)到服务器进行确认。如果每个跨域请求都伴随一次预检,将产生大量额外网络开销,严重影响应用性能。此时,通过Nginx配置跨域缓存,可以显著优化这一过程。
二、原因分析
根据CORS规范,对于非简单请求(例如使用了自定义请求头或非GET/POST/HEAD方法),浏览器必须首先使用OPTIONS方法发起一个预检请求,以获知服务器是否允许该实际请求。服务器通过响应头Access-Control-Max-Age来告知浏览器,可以将本次预检请求的结果缓存一段时间。在此时间内,对同一URL的相同请求方法,浏览器将直接使用缓存结果,而不再发送预检请求。Nginx作为高性能的反向代理服务器,可以方便地为此类响应添加缓存控制头,从而减少不必要的网络往返,提升应用响应速度。
三、详细解决步骤
以下步骤将指导你如何在Nginx配置中,为OPTIONS请求的响应添加跨域缓存头,并处理常规跨域请求。
步骤1:定位并编辑Nginx配置文件
首先,找到你的Nginx配置文件,通常位于/etc/nginx/nginx.conf或/etc/nginx/sites-available/目录下的站点配置文件。使用文本编辑器打开。
sudo vim /etc/nginx/sites-available/your-site.conf
步骤2:在Server或Location块中添加跨域处理规则
在需要启用跨域的server块或特定的location块中,添加以下配置。这里以处理API请求的location /api/为例。
server {
listen 80;
server_name example.com;
location /api/ {
# 处理预检请求 (OPTIONS)
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
# 关键:设置预检请求缓存时间为86400秒(24小时)
add_header 'Access-Control-Max-Age' 86400 always;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# 处理实际的跨域请求
if ($request_method != 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
}
# 你的代理配置或根目录设置
proxy_pass http://backend_server;
# 或其他处理逻辑
# root /path/to/your/app;
}
}
步骤3:检查配置语法并重载Nginx
保存配置文件后,务必使用nginx -t命令测试配置语法是否正确。确认无误后,重载Nginx使配置生效。
sudo nginx -t
sudo systemctl reload nginx
# 或者使用 service nginx reload
步骤4:验证配置效果
配置生效后,你可以使用浏览器的开发者工具或curl命令测试。首次发送一个非简单跨域请求(如带自定义头的POST请求),观察网络面板,应该会看到一次OPTIONS预检请求。随后,在缓存有效期内(本例为24小时)再次发送相同请求,浏览器应直接发送实际请求而不再发送预检请求。
# 使用curl模拟一个带自定义头的POST请求(预检)
curl -X OPTIONS -H "Origin: http://client-domain.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: Authorization" -I http://example.com/api/endpoint
检查返回的响应头中是否包含Access-Control-Max-Age: 86400。
四、注意事项
配置时需注意:Access-Control-Max-Age的值不宜设置过大,需根据业务更新频率权衡。确保Access-Control-Allow-Origin的值(如$http_origin)符合安全要求,生产环境建议指定具体域名而非通配符*。如果Nginx配置中add_header指令在其他地方被覆盖,需要使用always参数确保始终添加这些头部。
五、适用环境
本配置适用于部署了Nginx作为Web服务器或反向代理,且需要优化跨域请求性能的前后端分离应用场景。
