Nginx+Express+Vuejs环境下部分静态资源加载过慢问题排查
- 服务器环境:Nginx + Express(Node.js) + Vue.js,Express返回Vue构建文件,整体功能正常,但部分静态资源加载耗时1分钟
- Nginx错误日志:
2023/09/13 19:32:45 [error] 3930470#3930470: 1 upstream timed out (110: Connection timed out) while connecting to upstream, client: ..., server: www.wradion.dev, request: "GET /assets/index.a2f3249e.css HTTP/1.1", upstream: "http://162.255.119.151:8080/assets/index.a2f3249e.css", host: "www.wradion.dev", referrer: "https://www.wradion.dev/xxxxxx"
2023/09/13 19:32:46 [error] 3930470#3930470: 5 upstream timed out (110: Connection timed out) while connecting to upstream, client: ...**, server: www.wradion.dev, request: "GET /assets/vendor.90419635.js HTTP/1.1", upstream: "http://162.255.119.151:8080/assets/vendor.90419635.js", host: "www.wradion.dev", referrer: "https://www.wradion.dev/xxxxxx"
- 错误影响:超时1分钟后资源正常返回,不导致网站故障
- 当前Nginx配置(sites-enabled/default):
server { # SSL configuration # listen 443 ssl default; listen [::]:443 ssl default; # certbot certificates conf root /var/www/wradion_dev/frontend/dist; server_name www.wradion.dev; location / { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_pass http://wradion.dev:8080; } location /socket.io { proxy_pass http://wradion.dev:8090; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } # Redirect non-www to www server { listen 443 ssl; listen [::]:443 ssl; # certbot certificates conf server_name wradion.dev; return 301 https://www.wradion.dev$request_uri; } server { listen 80 default; server_name _; }
- 需求:找出问题根源,实现Nginx直接提供静态资源
- 静态资源全部走代理导致超时:当前Nginx把所有请求(包括静态资源)都代理到Express的8080端口,但
wradion.dev解析到的162.255.119.151可能存在网络连通性问题,或者Express处理静态资源时响应缓慢,导致Nginx等待上游超时1分钟。 - 未利用本地静态文件配置:Nginx配置里已经指定了Vue构建文件的根目录
root /var/www/wradion_dev/frontend/dist;,但因为location /的代理规则优先级更高,所有请求都走了代理,没有让Nginx直接读取本地静态文件,浪费了Nginx静态资源服务的性能优势。
修改Nginx配置,让静态资源请求直接由Nginx处理,仅将非静态资源(如API请求、SPA路由)代理到Express:
server { listen 443 ssl default; listen [::]:443 ssl default; # certbot certificates conf root /var/www/wradion_dev/frontend/dist; server_name www.wradion.dev; # 直接处理静态资源请求,跳过代理 location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 30d; # 设置静态资源缓存有效期,提升重复访问速度 add_header Cache-Control "public, immutable"; } # Vue SPA路由处理:先尝试本地文件,不存在则走代理 location / { try_files $uri $uri/ @proxy_to_node; } # 代理非静态资源和SPA路由到Express location @proxy_to_node { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; proxy_pass http://wradion.dev:8080; # 缩短超时时间,避免用户等待1分钟 proxy_connect_timeout 10s; proxy_send_timeout 10s; proxy_read_timeout 10s; } location /socket.io { proxy_pass http://wradion.dev:8090; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } # Redirect non-www to www server { listen 443 ssl; listen [::]:443 ssl; # certbot certificates conf server_name wradion.dev; return 301 https://www.wradion.dev$request_uri; } server { listen 80 default; server_name _; # 将80端口请求重定向到HTTPS return 301 https://www.wradion.dev$request_uri; }
- 静态资源规则:通过正则匹配常见静态资源后缀,Nginx直接读取本地
root目录下的文件返回,无需经过Express,彻底解决代理超时问题,同时设置缓存头提升重复访问性能。 - SPA路由兼容:用
try_files优先尝试读取本地文件,不存在的路径(Vue路由)再代理到Express,保证单页应用路由正常工作。 - 超时优化:缩短代理连接、发送、读取的超时时间,避免用户长时间等待,同时如果Express出现故障,能更快返回错误提示。
内容的提问来源于stack exchange,提问作者wRadion

