一、优先用 return
return 301 https://www.it586.cn$request_uri;
return 302 /login;
return 404;
return 直接返回状态码或跳转,性能好、语义清晰。能用 return 就不要用 rewrite,后者要跑正则、还要考虑 flag 的作用范围。
二、rewrite 的四个 flag
rewrite ^/old/(.*)$ /new/$1 permanent;
| flag | 行为 |
|---|---|
last | 重写后重新匹配 location(最常用) |
break | 重写后停止,在当前 location 继续处理 |
redirect | 返回 302 |
permanent | 返回 301 |
last 与 break 的区别很实际:last 会再走一遍 location 匹配,可能命中另一条规则;break 就地处理完。写内部重写时用 last,做 URI 改写后直接给静态文件时用 break。
三、单页应用(SPA)刷新 404
React/Vue 的 /user/123 是前端路由,服务器上并没有这个文件,直接刷新就 404。解决:
location / {
root /var/www/app;
try_files $uri $uri/ /index.html;
}
含义:先找真实文件,再找目录,都没有就返回 index.html,由前端路由接管。
注意别把它用在有真实 404 需求的站点上,否则所有错误 URL 都返回 200 首页,形成软 404。
四、旧链接批量 301
改版换路径时,逐条写太麻烦,可以按前缀批量转:
# /blog/xxx → /articles/xxx
rewrite ^/blog/(.*)$ /articles/$1 permanent;
# 老域名整体跳新域名
server {
listen 80;
server_name old-domain.com;
return 301 https://www.it586.cn$request_uri;
}
上线前把常见旧 URL 列出来,用 curl -I 逐个确认返回 301 且 Location 正确。301 会被浏览器强缓存,测错了很难回滚,所以测试阶段先用 302,确认无误再改 301。
五、末尾斜杠统一
# 目录补斜杠(避免相对路径错乱)
if (-d $request_uri) {
rewrite ^(.*[^/])$ $1/ permanent;
}
if 在 location 里要谨慎使用(有「if is evil」的说法),能用 try_files 或独立 location 解决就别用。更简单的做法是:站内链接统一不带斜杠,或统一带斜杠,从源头避免两套 URL。
六、去掉 index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
这样 /article/1 会交给 index.php 处理,URL 里不再出现 index.php。
七、调试技巧
curl -I https://www.it586.cn/old/path # 只看响应头
curl -sIL https://a.com/x | grep -E "HTTP/|location" # 跟踪整条跳转链
-L 跟随跳转,能看到最终落地页和中间每一步。跳转成环(A→B→A)时浏览器报 too many redirects,用 -sIL 一眼就能看出环在哪。
Nginx 侧可以临时打开 rewrite_log on;(需 error_log notice)看规则命中情况,排查完记得关掉。
八、SEO 注意
- 永久迁移用 301,临时活动用 302。
- 跳转目标应是最终规范 URL,不要 301 到一个又 302 的地址(跳转链会损失权重)。
- 跳转后页面的
canonical要与最终 URL 一致。 - 不要把所有错误都跳首页,那会让搜索引擎认为大量页面内容重复。
小结
优先 return;rewrite 的 last 会重新匹配、break 就地处理;SPA 用 try_files ... /index.html;批量迁移用前缀正则 301;测试阶段先用 302。