前言
有一天,老板突然登录后台管理系统,说系统卡住了,无法登录,让我马上和运维排查问题
从点击登录到卡住,返回请求错误码足足等待了超过30S,老板挂面,我可能有被裁风险
排查问题
点击登录以后,前端请求后端的接口,这里的流程是前端通过跨域请求实现的。 方式是通过 nginx
服务器代理请求后端的接口的。
我们定位到 nginx
处理跨域请求的时候的配置上。
Nginx 在使用 proxy_pass
进行域名代理时,可能会出现缓存问题,导致后端服务更新后客户端无法及时获取最新内容。这通常由多种因素引起,包括 Nginx 自身缓存、上游服务器缓存头设置或浏览器缓存策略等诸多因素,我们一个个进行排查
一,确认缓存的来源
在解决问题前,需先确定缓存位置:
- 浏览器缓存:通过开发者工具(如 Chrome 的 Network 面板)检查响应头中的
Cache-Control
和Expires
。 - Nginx 代理缓存:检查 Nginx 配置是否启用了
proxy_cache
或相关指令。 - 上游服务器缓存:检查后端应用是否设置了缓存头。
很容易我们就排除了浏览器的缓存和上游服务器后端的缓存,前端浏览器这边 Cache-Control Expires 已经设置好响应头,同时后端应用也设置好了缓存头
接下来我们将问题定位到运维的位置
二、禁用 Nginx 代理缓存
在处理跨域请求(CORS)时,Nginx 需要同时解决两个关键问题:跨域头配置和禁用缓存。以下是针对这两个需求的配置方案:
一、基础配置:跨域头 + 禁用缓存
server {
listen 80;
server_name your-domain.com;
# 处理跨域请求
location /api/ {
# 代理配置
proxy_pass http://backend-api-server/; # 后端 API 服务器地址
# 跨域头配置
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
# 允许携带凭证(如 cookies)
add_header 'Access-Control-Allow-Credentials' 'true' always;
# OPTIONS 请求直接返回 204
if ($request_method = 'OPTIONS') {
return 204;
}
# 禁用缓存配置
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
# 其他代理常用配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
二、高级配置:针对不同请求类型优化
1. 静态资源与动态 API 差异化处理
server {
# 静态资源(允许缓存)
location /static/ {
proxy_pass http://backend-static/;
# 默认缓存策略(根据需要调整)
expires 7d;
}
# API 请求(禁用缓存)
location /api/ {
proxy_pass http://backend-api/;
# 跨域头
add_header 'Access-Control-Allow-Origin' '*' always;
# ... 其他 CORS 头
# 禁用缓存
proxy_no_cache 1;
proxy_cache_bypass 1;
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
}
2. 仅对特定 API 禁用缓存
location /api/no-cache/ {
proxy_pass http://backend/;
# 禁用缓存
proxy_no_cache $arg_nocache;
proxy_cache_bypass $arg_nocache;
# 动态添加 nocache 参数来控制是否缓存
# 例如:/api/no-cache/data?nocache=1
}
3. 针对常用写死的域名,让每次请求都进行 DNS 查询
http {
resolver 8.8.8.8 valid=10s;
server {
listen 80;
location / {
set $upstream_host a.b.com;
proxy_pass https://$upstream_host;
proxy_set_header Host $upstream_host;
}
}
}
三、验证配置是否生效
1. 检查响应头
curl -I http://your-domain.com/api/data
# 预期输出:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,...
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
2. 浏览器开发者工具验证
在 Chrome/Firefox 中:
- 打开开发者工具 → Network 面板
- 发送请求并检查响应头
- 确认没有
(from cache)
标记
通过以上配置,可确保 Nginx 在处理跨域请求时正确禁用缓存,同时满足 CORS 安全要求。根据具体业务需求调整配置细节,平衡性能与安全性。
三、 常见问题与解决方案
缓存仍未完全禁用
-
问题原因:
- 上游服务器设置了缓存头,覆盖了 Nginx 的配置
- CDN 缓存未清除
- 浏览器强缓存
-
解决方案:
- 使用
proxy_ignore_headers Cache-Control Expires
忽略上游缓存头 - 若使用 CDN,在 CDN 控制台刷新缓存
- 要求用户使用
Ctrl+F5
(Windows)或Command+Shift+R
(Mac)强制刷新
- 使用
Nginx 配置生效部分
修改配置后需重启或重载 Nginx:
sudo nginx -s reload
总结
前端针对这种问题需要提前做预防措施,为了避免
预防措施
- 开发阶段:
- 使用代理服务器处理跨域(如 Vite 的
server.proxy
) - 在浏览器开发者工具中始终启用「Disable cache」
- 生产环境:
- 对静态资源使用版本化(如
app.js?v=1.0.1
) - 为 API 请求设置合理的缓存策略(如频繁更新的数据使用
no-cache
) - 定期审查服务器和 CDN 的缓存配置
解决方案总结
问题类型 | 解决方案 |
---|---|
跨域错误 | 1. 修改服务器 Nginx 配置,添加正确的 CORS 头 2. 使用代理服务器(如 Vite/Webpack 代理) 3. 确保请求配置与服务器允许的范围一致 |
浏览器缓存 | 1. 在开发者工具中禁用缓存 2. 添加响应头 Cache-Control: no-cache 3. 请求 URL 添加随机参数 |
服务器缓存 | 1. 修改后端代码,禁用缓存头 2. 检查 Nginx 配置,确保正确设置 proxy_no_cache |
CDN 缓存 | 1. 在 CDN 控制台刷新缓存 2. 调整 CDN 缓存规则(如设置 Cache-Control: no-cache ) |
至此完结