一直对nginx处于比较浅显的了解,趁着这次调试项目,对了解到的nginx也做一次总结。
问题背景:
本地vite项目运行正常,但是部署到对应环境后,页面无法正常访问。
预计此问题是未正常请求到资源导致返回了兜底的
html内容,然而请求的是js文件,得到的却是html文件,所以导致的此报错。查看了
vite.config.ts,发现当前base配置是./【相对路径】,将其修改为/【绝对路径】后,希望在本地确认一下是否正常后再部署到对应环境,就有了以下流程。
调试过程:
先在本地执行对应环境的打包命令:pnpm run build:test,会在项目根目录下生成dist文件。
由于Vite中内置的Vite preview不支持代理,所以无法使用pnpm run preview直接运行dist。
此时选择使用Nginx运行本地dist。
在本地nginx配置中添加对此项目的代理:
# 所有行都需要 ; 结尾
...
server {
# 监听端口号
listen 3333;
# 配置后在浏览器中的地址就是localhost:3333
server_name localhost;
# 静态文件目录【使用绝对路径】
root E:/work/object/dist;
index index.html;
# 静态资源缓存
location~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|wasm)$ {
expires 1y;
}
# API 代理
location /api/ {
proxy_pass http://1.1.1.1:1111;
client_max_body_size 500m; # 允许上传最大 500MB 文件
proxy_connect_timeout 600; # 连接超时 600 秒
proxy_send_timeout 600;
proxy_read_timeout 600; # 读取超时 600 秒
}
# SPA 路由支持
location / {
# 文件查找顺序 先找精确路径(/aa.html) 再找目录(/aa/) 最后用备用页面(回退到首页)
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = 50x.html {
root html;
}
}
...
重启nginx:
# 进入nginx.exe所在目录
# 1. 停止Nginx
./nginx -s stop
# 2. 重新加载配置
./nginx -s reload
# 3. 检查 Nginx 进程
tasklist | findstr nginx
除了以上方法也可以在任务管理器中手动停止对应的nginx进行后,再双击nginx.exe启动
nginx正常运行后,就可以在浏览器中直接访问了http:localhost:3333。发现修改base的设置后,确实解决了上述问题。就可以正常提交代码并在对应环境部署了。
问题解析
此次问题是因为新增了一个二级路由,当以base: "./"设置访问子路由/second/page时,
当前URL为:http://localhost:3333/second/page
资源路径为:./assets/xxx.js
解析结果为:http://localhost:3333/second/assets/xxx.js❌
浏览器会基于当前路径解析相对路径,./assets/xxx.js被解析成了second/assets/xxx.js,而实际文件在/assets/xxx.js,所以导致资源文件404,服务器返回了index.html【SPA fallback】,但浏览器期望js文件,因此报错Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of 'text/html'。
这个问题没有在本地运行时报错,是因为vite开发服务器会动态处理所有请求,不受base配置影响。
其他补充:
-
正向代理:
Nginx作为客户端代理,通常用于VPN、翻墙、公司内网代理
# 公司内网代理配置 # 员工电脑配置代理:192.168.1.100:3128 # 所有外网请求都通过这个代理 server { listen 3128; # 常用代理端口 server_name proxy.example.com; resolver 8.8.8.8; # DNS 服务器地址 # 允许的客户端IP(安全) allow 192.168.1.0/24; 只允许内网 deny all; location / { proxy_pass http://$http_host$request_uri; # 动态目标 proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_buffering off; # 关闭缓冲,提高性能 # 日志 access_log logs/proxy_access.log; } } -
反向代理:
Nginx作为服务器代理,上面的例子就是反向代理
localtion /api/ { proxy_pass http://1.1.1.1:7788; # 转给后端 } -
负载均衡:
可以设置自动轮询,设置权重,或者自定义
# 多个后端,按权重分配请求 upstream backend { server localhost:8080 weight=3; # 权重 3 server localhost:8081 weight=1; # 权重 1 server localhost:8082 backup; # 备用服务器 } server { location /api/ { proxy_pass http://backend; # 使用负载均衡 } } -
静态文件处理:
server { root E:/work/app/dist; # 文件仓库【绝对路径】 location / { try_files $uri $uri/ /index.html; } } -
Gzip压缩传输前压缩,可以减少带宽
图片、视频、PDF等如果已经压缩过,就不需要再压缩了,再次压缩效果差
小文件压缩收益小,反而增加CPU开销
http { gzip on; # 开启压缩 # 压缩级别(1-9,数字越大压缩越好但越慢) gzip_comp_level 6; # 推荐 6,平衡压缩率和速度 # 大于 1KB 才压缩,太小压缩意义不大 gzip_min_length 1024; # 压缩的文件类型 gzip_types text/plain # 纯文本 text/css # CSS text/javascript # JavaScript application/javascript application/json # JSON text/xml # XML application/xml application/xml+rss text/html; # HTML # 压缩缓冲区大小 gzip_buffers 16 8k; # 16个8KB缓冲区 # 是否添加 Vary: Accept-Encoding 头 # 告诉缓存服务器支持压缩 支持压缩的浏览器给压缩版,不支持的给原版 gzip_vary on; # 禁用某些浏览器的压缩(旧版 IE) gzip_disable "msie6"; # 禁用 IE6 } -
缓存控制
静态资源缓存,减少重复请求,减轻服务器压力
第一次请求:
浏览器 -> 服务器 -> 返回文件 -> 浏览器(同时缓存)第二次请求:
浏览器 -> nginx -> 直接返回缓存# 静态资源(JS、CSS、图片)- 长期缓存 location ~* .(js|css|png|jpg)$ { expires 1y; # 缓存1年 -1【不缓存】| epoch【不缓存】 | max【最大缓存时间10年】| 1y【一年】| 1M【一个月】... # 更详细的缓存规则 公共缓存,1年有效,不会改变 add_header Cache-Control "public, max-age=31536000, immutable"; access_log off; # 不记录访问日志(可选) } # HTML文件 - 短期缓存或不缓存 location ~* .html$ { expires 1h; # 缓存1小时 add_header Cache-Control "public, max-age=3600"; } # API响应 - 不缓存 location /api { proxy_pass http://localhost:8080; add_header Cache-Control "no-cache, no-store, must-revalidate"; } # 其他文件 location / { try_files $uri $uri/ /index.html; }Cache-Control参数说明:指令 含义 比喻 public 可以被任何缓存存储 公共货架,谁都能用 private 只能被浏览器缓存 私人货架,只有你能用 max-age=秒数 缓存有效期(秒) 保质期 immutable 文件不会改变 永久不变 no-cache 需要验证才能使用 每次都要检查 no-store 不缓存 不放在货架上 -
HTTPS【SSL】
server { listen 443 ssl; # HTTPS 端口 server_name example.com; # SSL证书配置 ssl_certificate /path/to/certificate.crt; # 证书文件 ssl_certificate_key /path/to/private.key; # 私钥文件 } -
限流
防止请求过多,保护服务器
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; location /api/ { limit_req zone=api_limit burst=20; # 每秒10个请求 proxy_pass http://localhost:8080; } -
跨域【CORS】
允许不同域名的前端访问API
location /api { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE'; add_header Access-Control-Allow-Headers 'Content-Type, Authorization'; proxy_pass http://localhost:8080; } -
重定向
URL变更,自动跳转
# 301 永久重定向 # 浏览器行为:记住新地址,下次直接访问;适用于域名变更或URL永久变更 location /old { return 301 /new; } # 302 临时重定向 # 浏览器行为:不记住,每次都询问;适用于临时维护、A/B测试 location /temp { return 302 /new; } -
请求头修改
location /api { proxy_set_header Host $host; # 设置Host proxy_set_header X-Real-IP $remote_addr; # 真实IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://localhost:8080; }