Nginx 的跳转配置核心就是 return 和 rewrite 两条指令。如果只是想让某个旧地址永久迁移到新地址,return 301 是最直接、性能开销最小的写法。它不像 rewrite 需要经过正则匹配和内部重写流程,执行到 return 会立即返回响应。理解这一点后,再根据自己是要做单页跳转、目录迁移,还是整站强制 HTTPS,把配置放进对应的 server 或 location 块里即可。

301、302 和 rewrite 各自适合什么场景
状态码本身已经说明了跳转性质:301 表示永久重定向,302 表示临时重定向。浏览器看到 301 后会把新地址缓存下来,下次直接访问旧地址也可能不再请求服务器,而是直接跳到新地址。这个特性对 SEO 友好,搜索引擎会把权重转移到新 URL。但开发调试阶段如果频繁更改跳转目标,301 缓存会让你误以为配置没生效。因此测试时可以优先用 302,确认目标无误后再改成 301。
rewrite 指令虽然也能完成重定向,但它的设计目标更偏向内部地址重写。通过正则表达式可以捕获动态路径并拼接成新地址,灵活性比 return 高。例如把 /blog/123 跳转到 /article/123,用 rewrite 加变量会非常方便。但如果只是固定地址跳转,仍推荐使用 return 301,因为 rewrite 会多走一次正则引擎,请求量大时性能差异会逐渐显现出来。
从执行逻辑看,return 属于 Nginx 的重写模块,但执行优先级很高,命中后直接返回,不会继续执行后续的 rewrite 规则。也就是说,当同一 location 里同时出现 return 和 rewrite 时,return 会优先生效。这个特性可以用来提前拦截某些不需要进入业务逻辑的请求,比如旧版接口路径。
单页跳转与目录迁移的完整配置
如果只有一个页面需要跳转,建议使用精确匹配的 location。这样不会误伤同前缀的其他路径。比如旧的活动页 /old-activity 需要指向新的活动页,配置可以这样写:
server {
listen 80;
server_name www.bbccb.com;
location = /old-activity {
return 301 /new-activity;
}
}
这里的 = 表示精确匹配,只对 /old-activity 这一个路径生效。如果目标是外部域名,必须写完整 URL,例如 return 301 https://www.bbccb.com/new-activity;。只写路径的情况下,Nginx 会默认使用当前域名拼接新路径,用户浏览器地址栏会显示当前域名下的新地址。
目录级跳转通常用于网站改版,比如把原来的博客目录 /blog/ 下的所有文章迁移到 /archive/ 目录。此时需要捕获路径后半段,可以用正则 location 加变量实现:
server {
listen 80;
server_name www.bbccb.com;
location ~ ^/blog/(.*)$ {
return 301 /archive/$1;
}
}
上面的 $1 代表正则里第一个括号捕获到的内容,也就是 /blog/ 后面的完整路径。如果访问 /blog/2024/how-to-optimize-nginx,会 301 到 /archive/2024/how-to-optimize-nginx。不过要注意,正则 location 的优先级高于普通前缀 location,如果不希望正则规则影响其他前缀路径,可以在普通前缀 location 前加上 ^~,这样 Nginx 会优先采用前缀匹配而跳过正则检查。
另外还有一种常见写法是使用 rewrite 完成同样的目录迁移:
server {
listen 80;
server_name www.bbccb.com;
location /blog/ {
rewrite ^/blog/(.*)$ /archive/$1 permanent;
}
}
permanent 参数会让 rewrite 产生 301 状态码。与 return 方案相比,这种写法更直观地表达了正则替换关系,但同样会让 Nginx 执行正则匹配。两种方式都可以实现需求,团队里若已有既定风格,保持一致即可。
整站 HTTP 跳转 HTTPS 的推荐写法
现在很多站点强制启用 HTTPS,理想做法是单独建一个监听 80 端口的 server 块,只负责把请求转到 443 端口。这样真正的业务配置集中在 HTTPS server 里,结构清晰,也方便后续维护证书相关参数。示例如下:
server {
listen 80;
server_name www.bbccb.com bbccb.com;
return 301 https://www.bbccb.com$request_uri;
}
server {
listen 443 ssl http2;
server_name www.bbccb.com bbccb.com;
ssl_certificate /etc/nginx/ssl/bbccb.com.crt;
ssl_certificate_key /etc/nginx/ssl/bbccb.com.key;
location / {
root /var/www/html;
index index.html;
}
}
这里的 $request_uri 包含完整路径和查询参数,例如用户访问 http://www.bbccb.com/product?id=5,跳转后地址会变成 https://www.bbccb.com/product?id=5,参数不会丢失。如果只写域名而不加变量,return 301 https://www.bbccb.com; 会把所有请求都指向首页,对用户体验和 SEO 都不理想。
若还需要把不带 www 的域名统一到带 www 的域名,可以再增加一个 80 端口 server 块,或者直接在现有 80 跳转逻辑中根据 $host 判断。比如只允许 www 域名提供服务,可以这样写:
server {
listen 80;
server_name bbccb.com;
return 301 https://www.bbccb.com$request_uri;
}
这样只有不带 www 的请求会被这条规则命中,带 www 的请求则进入上面配置的 80 跳转 server 块再转到 HTTPS。多个 server 块之间靠 server_name 区分,Nginx 会优先选择最精确匹配的 server 块处理请求。若一个请求没有匹配到任何 server_name,则会使用默认 server 块,这往往是跳转配置不生效的根源之一。
排错思路与新手常见误区
遇到配置修改后不生效,先确认两件事:测试环境是否被浏览器缓存,以及 Nginx 是否真的加载了新配置。301 缓存非常顽固,Chrome 会长期记住跳转结果。建议先用命令 curl -I http://www.bbccb.com/old-path 查看响应头,如果返回的 Location 符合预期,那多半是浏览器缓存问题。换一个路径测试或清空缓存通常就能看到新效果。修改配置后别忘了执行 nginx -t 校验语法,再用 nginx -s reload 平滑加载。
重定向循环是另一个高频问题,典型表现是浏览器提示重定向次数过多。原因通常是 A 跳到 B,B 又跳回 A。比如 80 端口跳到 HTTPS,而 HTTPS server 里又有一条规则把某些路径跳回 HTTP。排查时可以通过多次 curl -I 观察每次返回的 Location,逐步确认跳转链。还有一种容易忽略的情况:端口监听写错,比如 HTTPS server 实际监听 443,但跳转目标写成了 https://www.bbccb.com:80,这同样会引发怪异的循环。
location 的选择也容易让人困惑。Nginx 的匹配顺序并不是按照配置文件里的先后顺序,而是先找精确匹配 =,再找带 ^~ 的前缀匹配,然后记录普通前缀匹配并等待正则匹配结果。所以当你发现正则规则抢了普通前缀规则的位置时,给普通前缀 location 加上 ^~ 就能解决。很多重定向不符合预期的问题,其实都源于 location 优先级理解有误。最后还要提醒一下,if 指令虽然能实现条件判断,但在 Nginx 中它容易带来隐患,尤其是和 rewrite 混用时可能出现非预期行为。除非确实需要根据变量做判断,否则优先用 server 块和 location 层级来分流。