ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nginx 反代 + 静态缓存 + 接口限流一次配齐,别再裸奔 Spring Boot 了

Nginx 反代 + 静态缓存 + 接口限流一次配齐,别再裸奔 Spring Boot 了 导读Spring Boot 应用直接 8080 端口对外暴露这是我在客户服务器上见过最多的情况——没有反代、没有缓存、没有限流被刷接口只能干瞪眼。这篇把一套能直接抄的 Nginx 配置拆开讲反向代理怎么配、静态资源怎么缓存、接口怎么限流以及两个让配置看起来对但实际没用的坑。为什么必须套一层 NginxSpring Boot 自带 Tomcat 能跑但有几个事它干不了或者干不好静态资源让 Tomcat 扛纯属浪费线程同一台机器要挂多个服务前端静态站 后端 管理后台端口都分不清被人拿脚本刷接口Tomcat 没有现成的限流手段。Nginx 一层全解决。反向代理proxy_pass 的坑先说基础配置长这样server { listen 80; server_name api.qkl.com; location /api/ { proxy_pass http://127.0.0.1:8080; 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_read_timeout 300s; } }这里有个经典坑proxy_pass后面带不带/行为完全不同。proxy_pass http://127.0.0.1:8080;不带斜杠/api/order/list原样转发成/api/order/listproxy_pass http://127.0.0.1:8080/;带斜杠/api/order/list会被替换成/order/list——location 前缀被剥掉了。我见过有人把带斜杠的配置当正常用结果后端接口 404排查半天。不带斜杠 保留原始 URI这是最常用的。X-Real-IP一定要配否则后端拿到的 clientIp 全是127.0.0.1做 IP 限流、风控全废。静态资源缓存命中率低到怀疑人生前端打包出来的 js/css/img 全是带 hash 的文件名这类资源可以放心长期缓存location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 30d; add_header Cache-Control public, immutable; access_log off; root /var/www/qkl-web; try_files $uri 404; }immutable是给带 hash 的资源用的——文件名不变内容就不变浏览器永远不用重新验证直接本地取。但注意index.html 千万不能这样缓存否则发版后用户看到的还是旧壳子。index.html 应该走no-cache每次都回源验证location /index.html { add_header Cache-Control no-cache, must-revalidate; }接口限流zone 定义 生效两个动作Nginx 限流分两步先在http块定义限流 zone再在 location 里引用http { # 按 IP 限流每秒 5 个超过进 10 个的桶 limit_req_zone $binary_remote_addr zoneapi_limit:10m rate5r/s; server { location /api/ { limit_req zoneapi_limit burst10 nodelay; proxy_pass http://127.0.0.1:8080; } } }burst10是给一个 10 个容量的队列瞬间打进来的请求先排队nodelay表示队列满了直接 429不等待。加了nodelay才真正挡人不加的话超限请求会被延时排队恶意刷的人反而把带宽耗满。限流返回的 429 不好看可以自定义limit_req_status 429;踩坑一limit_req_zone 写进了 server 块Nginx -t 直接报错问题现象照着网上的配置贴nginx -t报limit_req_zone directive is not allowed here。排查过程看报错位置limit_req_zone被写在了server { }里。查文档这个指令只允许出现在 http 块它定义的是共享内存 zone必须全局可见。而limit_req引用 zone 的那条才写在 location 里。定位思路把limit_req_zone提到 http 块两个位置分清楚定义在 http、使用在 location。最终解决nginx -t通过。这个错本质是搞混了定义指令和使用指令的层级。踩坑二缓存配了但命中率还是 0%问题现象静态缓存配置好浏览器 DevTools 看请求js/css 全是200 from disk cache变304甚至200回源expires 30d像没生效。排查过程先看响应头Cache-Control: max-age2592000有但请求头带了Cache-Control: no-cache——是前端代码或者开发者工具勾了Disable cache。换无痕窗口看正常命中。定位思路缓存不生效先分三层查响应头有没有max-age、请求头有没有被禁缓存、Nginx 层有没有add_header被覆盖。我这里第三层才是真坑add_header在带immutable的 location 里生效但同 server 的另一个 location 里也 add 了别的头Nginx 的 add_header 是同级别继承、不同级别覆盖子 location 定义了 add_header 就不会继承父级。最终解决把缓存相关的add_header集中在对应 location 里写全不再依赖继承。可直接复用的清单proxy_pass不带/ 保留原始 URI带/ 剥前缀二选一别搞混反代必须配X-Real-IP后端才拿得到真实 IP带 hash 的静态资源immutable缓存 30 天index.html 必须no-cache限流两段式limit_req_zone在 http 块定义、limit_req在 location 使用加nodelayadd_header同 location 写全别依赖跨 location 继承。这套配置在宝塔面板里同样适用改改路径就能用。
返回列表