Nginx 的 returnrewrite 指令是日常运维中使用频率极高的两个工具:前者直接返回状态码(常用于 301 永久跳转),后者通过正则改写 URL 内部路径。本文讲清两者的区别、典型用法和各类框架的伪静态规则写法,配合真实示例,帮你快速掌握。

本文要点

  • return 301rewrite 的核心区别
  • 常见跳转场景:www↔根域、HTTP→HTTPS、旧路径→新路径
  • WordPress、Discuz、Laravel 等主流程序的伪静态规则
  • rewrite 正则的 flag:last、break、redirect、permanent
  • 调试重定向的实用技巧

return vs rewrite:先搞清区别

指令处理阶段主要用途性能
return早期,无需正则直接返回响应码与 URL更快
rewrite正则匹配后改写 URI,可内部跳转或外部重定向略慢

能用 return 解决的场景,优先用 return;需要根据 URL 内容做复杂变换才用 rewrite

return 301 常见用法

HTTP 强制跳转到 HTTPS

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

www 跳转到根域(去 www)

server {
    listen 443 ssl;
    server_name www.example.com;
    # ssl 配置...
    return 301 https://example.com$request_uri;
}

根域跳转到 www(加 www)

server {
    listen 443 ssl;
    server_name example.com;
    # ssl 配置...
    return 301 https://www.example.com$request_uri;
}

旧路径跳转到新路径

# 单条旧路径跳转
location = /old-page.html {
    return 301 /new-page.html;
}

# 旧目录整体跳转
location ^~ /old-blog/ {
    return 301 /blog/;
}

注意保留请求参数

使用 $request_uri(含查询参数)而非 $uri(不含查询参数)进行跳转,避免 SEO 或功能依赖参数的页面丢失参数。

rewrite 指令详解

基本语法

rewrite 正则 替换字符串 [flag];

flag 含义

flag含义
last内部重新搜索 location(最常用)
break停止处理后续 rewrite,在当前 location 继续
redirect临时 302 跳转(外部重定向)
permanent永久 301 跳转(外部重定向)

rewrite 示例

# 去掉 .html 后缀(访问 /about 自动处理 about.html)
rewrite ^/(.+)\.html$ /$1 permanent;

# 把 /product/123 转写为 /product.php?id=123
rewrite ^/product/(\d+)$ /product.php?id=$1 last;

常见框架伪静态规则

WordPress

location / {
    try_files $uri $uri/ /index.php?$args;
}

Laravel / 其他 PHP MVC 框架

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Discuz!

location / {
    try_files $uri $uri/ /index.php;
}

location ~* \.php$ {
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Typecho

location / {
    index index.php;
    if (-f $request_filename/index.php){
        rewrite (.*) $1/index.php break;
    }
    if (-f $request_filename/index.html){
        rewrite (.*) $1/index.html break;
    }
    if (!-f $request_filename){
        rewrite (.*) /index.php last;
    }
}

优先用 try_files

对于 PHP 框架的伪静态,try_files 写法比复杂 rewrite 更简洁高效。WordPress、Laravel 等主流框架官方也推荐 try_files 写法。

调试重定向

# 查看跳转链(不自动跟随跳转)
curl -I http://example.com

# 跟随所有跳转,显示最终落地页
curl -ILv http://example.com

# 本地快速测试(无需配置 DNS)
curl -H 'Host: example.com' http://127.0.0.1/

浏览器有重定向缓存

301 跳转会被浏览器缓存,开发调试时频繁改跳转规则,建议用 curl 而非浏览器测试,避免缓存干扰。Chrome 无痕模式 + 禁用缓存也可以。

小结

  • 优先用 return 301,它快且不需要正则
  • rewrite + last 适合内部路径改写;permanent 适合外部 301
  • PHP 框架伪静态优先用 try_files 写法
  • 调试跳转用 curl -ILv,避免浏览器缓存干扰

常见问题

return 301 和 rewrite permanent 有什么区别?

结果相同,都返回 301 状态码。return 301 更简洁高效,不需要正则匹配;rewrite permanent 需要先匹配正则再重定向,性能略差。优先用 return 301。

为什么改了跳转规则浏览器还是走旧的?

301 跳转被浏览器缓存,需要清空浏览器缓存或用无痕窗口测试。改为 302 临时测试完成后再改回 301 也是常用技巧。

try_files 和 rewrite 哪个适合 PHP 框架?

优先用 try_files,写法简洁且性能更好。大多数主流 PHP 框架(WordPress、Laravel、ThinkPHP)官方文档都推荐 try_files 写法。

rewrite 的 last 和 break 有什么区别?

last 会重新在所有 location 中搜索匹配(可能再次触发其他 location);break 停止当前 rewrite 规则组,在当前 location 内继续处理,不会重新搜索 location。