nginx地址重定向和重写

 

简单来说,重定向是告诉客户端“你要的资源在另一个地方,请去那里找”,而重写是服务器内部“悄悄地”把请求换个样子来处理,客户端对此一无所知。

下面我们详细解释并举例说明。


核心区别

特性重定向 (Redirect)重写 (Rewrite)
本质 客户端行为 服务器内部行为
HTTP响应 返回 3xx 状态码(如301, 302) 不返回3xx状态码(除非显式指定)
浏览器地址栏 会变化为新的URL 不会变化(因为是内部处理)
请求次数 至少2次(客户端收到重定向指令后,会发起新请求) 1次(服务器内部处理,对客户端透明)
性能 稍差,因为多了额外的网络往返 更好,减少了客户端往返
主要指令 returnrewrite (带 redirect 或 permanent 标志) rewrite (不带重定向标志)
常见场景 域名变更、强制HTTPS、URL标准化 美化URL、动态URL映射、条件性路由

一、重定向 (Redirect)

重定向是服务器向客户端发送一个特殊的响应(HTTP状态码 3xx),指示客户端重新向一个新的URL发起请求。

主要指令:return

return 指令非常高效,通常用于直接返回状态码和URL。

举例说明:

  1. 经典场景:强制所有HTTP请求跳转到HTTPS

    server {
        listen 80;
        server_name example.com;
        # 使用return 301进行永久重定向
        return 301 https://$server_name$request_uri;
    }
    • 过程:用户访问 http://example.com -> Nginx返回 301 Moved Permanently 和 Location: https://example.com -> 浏览器自动跳转到 https://example.com

    • 效果:地址栏变化。

  2. 域名重定向:将旧域名跳转到新域名

    nginx
    server {
        listen 80;
        server_name old-site.com;
        # 将旧域名的所有请求重定向到新域名的对应页面
        return 301 https://new-site.com$request_uri;
    }
    • 过程:访问 http://old-site.com/about.html -> 浏览器跳转到 https://new-site.com/about.html

    • 效果:地址栏变化。

 

二、重写 (Rewrite)

重写是服务器在内部修改接收到的请求的URI,然后根据修改后的URI继续处理(如交给其他location处理或返回内容),客户端浏览器感知不到这个变化。

主要指令:rewrite

rewrite 指令的语法是:rewrite regex replacement [flag];

常用 flag:

  • last:用replacement重写后,跳出当前规则,重新用新的URI在server上下文中匹配location。

  • break:用replacement重写后,停止后续的rewrite规则,并在当前location中继续处理。

  • permanent:这不是内部重写,而是会返回 301 永久重定向给客户端。这实际上属于上面“重定向”的范畴。

举例说明:

  1. 美化URL(前端控制器模式)
    这是最常见的作用。将动态的、复杂的URL重写为简洁美观的格式。

    • 真实URL: /index.php?article=123

    • 美化后想让用户看到的URL: /articles/123

    server {
        root /var/www/html;
        location / {
            # 尝试直接访问文件或目录,如果不存在...
            try_files $uri $uri/ /index.php?$args;
        }
    
        location ~ \.php$ {
            # ... PHP-FPM配置 ...
        }
    
        # 重写规则:将 /articles/123 内部映射为 /index.php?article=123
        rewrite ^/articles/(\d+)$ /index.php?article=$1 last;
    }
    • 过程:用户请求 /articles/123 -> Nginx内部将其重写为 /index.php?article=123 -> 继续匹配 location ~ \.php$ 来处理这个请求 -> 返回结果给用户。

    • 效果:用户浏览器地址栏始终保持 /articles/123,不知道后台其实是 index.php 在干活。

  2. 条件性重写(if判断)

    # 如果请求的文件不存在,则重写到一個默认图片
    if (!-f $request_filename) {
        rewrite ^/images/(.*)$ /images/default.png break;
    }
    • 过程:请求 /images/photo.jpg(如果该文件不存在)-> Nginx内部将请求修改为 /images/default.png -> 返回默认图片。

    • 效果:用户浏览器地址栏仍然是 /images/photo.jpg,但看到的是 default.png 的内容。


三、rewrite 指令的双重角色

需要注意的是,rewrite 指令根据使用的 flag 不同,可以扮演两种角色:

  1. 内部重写(服务器行为):当使用 last 或 break 时。

  2. 外部重定向(客户端行为):当使用 permanent 或 redirect 时。

重定向示例(使用 rewrite):

# 临时重定向 (302)
rewrite ^/old-page$ /new-page redirect;

# 永久重定向 (301)
rewrite ^/old-page$ /new-page permanent;

这和使用 return 301 /new-page; 效果类似,但 return 指令更直接高效,通常作为重定向的首选。

总结

你的需求应使用示例
告诉用户/搜索引擎URL已永久变更 重定向 (return 301) return 301 https://$host$request_uri;
临时将用户引导到另一个页面 重定向 (return 302 或 rewrite ... redirect) return 302 /maintenance.html;
美化URL,隐藏真实后端脚本 重写 (rewrite ... last) rewrite ^/blog/(\d+)$ /index.php?id=$1 last;
根据条件(如文件不存在)改变请求目标 重写 (rewrite ... break) if (!-f $request_filename) { rewrite ... break; }

简单记法:看浏览器地址栏会不会变。会变的是重定向,不变的是重写。

 

四、rewrite 指令的flag区别

好的,我们来深入探讨Nginx rewrite 指令中几个核心 flag 的区别。理解这些标志是掌握Nginx重写规则的关键。

最常用的四个标志是:lastbreakpermanentredirect
它们可以分为两大类:

  1. 内部处理类 (lastbreak):用于服务器内部重写URI,不会让客户端发起新请求。

  2. 客户端重定向类 (permanentredirect):会中断处理并向客户端返回一个重定向响应(3xx),会让客户端发起新请求。


内部处理类 Flag

这类Flag的特点是:浏览器地址栏不会改变,整个过程在服务器内部完成。

1. last

  • 行为:停止当前轮的 rewrite 模块指令,用重写后的新URI,重新发起一轮新的请求匹配。新的URI会重新匹配 server 块中的 location

  • 过程比喻:就像在一个办公室里,A部门的员工(当前location)把你的申请单(请求URI)修改了一下,然后对你说:“这个不归我们管,你拿着这个新单子,重新去前台问一下该去哪个部门吧。” 于是你回到前台,前台根据新单子把你指引到B部门。

  • 搜索范围:会重新搜索 server 级别的所有 location

  • 使用场景:非常通用,是大多数重写规则的首选,特别是当重写后的URI需要被另一个 location 块处理时。

示例:

location /api/ {
    rewrite ^/api/(.*)$ /app/index.php?route=$1 last;
}

location ~ \.php$ {
    # 处理PHP请求的配置(FastCGI等)
    ...
}

流程:

  1. 请求 /api/users/1

  2. rewrite 规则匹配,URI被重写为 /app/index.php?route=users/1

  3. last 标志触发,Nginx重新开始查找能处理 /app/index.php?route=users/1 的 location

  4. 新的URI匹配到 location ~ \.php$,请求被交给PHP解释器处理。


2. break

  • 行为:停止当前轮的 rewrite 模块指令,并且不再重新匹配location,直接在当前location中继续处理重写后的URI。

  • 过程比喻:还是那个办公室,A部门的员工修改了你的申请单,然后说:“行了,我知道接下来该怎么处理了,你就在这等着吧。” 他不会再让你去前台重新问路。

  • 搜索范围:不会重新搜索 location。只在当前上下文中继续。

  • 使用场景:

    • 在非 location 块(如 server 块)中使用时,重写后继续正常处理(如尝试查找文件)。

    • 在 location 块中,当你确信重写后的URI就应该由当前这个 location 处理,或者只需要进行简单的文件路径映射时。

示例:

# 示例1:在server块中,将 /static/* 映射到 /data/assets/*
server {
    ...
    rewrite ^/static/(.*)$ /data/assets/$1 break;

    # 重写后,Nginx会尝试寻找文件 /data/assets/css/style.css
    # 而不会重新匹配location
    ...
}

# 示例2:在location块中
location /images/ {
    # 如果文件不存在,则提供默认图片
    if (!-f $request_filename) {
        rewrite ^/images/(.*)$ /images/default.jpg break;
    }
    # break后,会直接尝试寻找 /images/default.jpg 文件
}

关键区别:last vs break
last 会发起新一轮location匹配,而 break 不会。如果上面的 last 示例错用了 break

nginx
 
location /api/ {
    rewrite ^/api/(.*)$ /app/index.php?route=$1 break; # 错误地使用了break
}
location ~ \.php$ {
    ...
}

流程会变成:

  1. 请求 /api/users/1

  2. URI被重写为 /app/index.php?route=users/1

  3. break 标志触发,Nginx停止重写,并尝试在当前 location /api/ 中处理 /app/index.php?route=users/1 这个请求。

  4. 由于 /api/ 这个location通常不配置处理PHP,最终很可能会返回404错误或直接下载PHP文件。


客户端重定向类 Flag

这类Flag的特点是:会中断当前请求,并向客户端返回一个重定向响应(3xx状态码),浏览器地址栏会变为新的URL。

3. permanent

  • 行为:返回 301 Moved Permanently(永久重定向)状态码给客户端。

  • 影响:搜索引擎会记住这个重定向,将权重和排名转移到新的URL上。

  • 使用场景:域名永久迁移、强制HTTPS、URL结构永久变更。这是SEO友好的做法。

示例:

nginx
 
# 永久将旧域名重定向到新域名
server {
    listen 80;
    server_name old.com www.old.com;
    return 301 https://new.com$request_uri; # 使用return更标准
    # 或者用 rewrite
    # rewrite ^(.*)$ https://new.com$1 permanent;
}

4. redirect

  • 行为:返回 302 Found(临时重定向)状态码给客户端。

  • 影响:搜索引擎不会记住这个重定向,认为这只是临时的。

  • 使用场景:临时维护页面、A/B测试等需要临时跳转的情况。

示例:

nginx
 
# 网站临时维护,跳转到维护页面
location / {
    rewrite ^(.*)$ /maintenance.html redirect;
}

总结与选择指南

Flag类型行为浏览器地址栏变化?常用场景
last 内部重写 停止当前重写,重新匹配location 通用重写,特别是需要PHP/代理处理的美化URL
break 内部重写 停止当前重写,在当前上下文继续 静态文件路径映射、在当前location内完成处理
permanent 客户端重定向 返回 301 永久重定向 永久性更改(域名、HTTPS、旧链接)
redirect 客户端重定向 返回 302 临时重定向 临时跳转(维护、测试)

简单选择原则:

  1. 你想让用户浏览器地址栏变吗?

    • 想变 -> 用 permanent (永久) 或 redirect (临时)。优先考虑更高效的 return 301/302 指令。

    • 不想变 -> 用 last 或 break

  2. 用 last 还是 break

    • 重写后的URI需要由另一个 location(如PHP处理块、代理转发块)来处理 -> 用 last

    • 重写后的URI就在当前上下文处理(如找另一个文件)-> 用 break。在 server 块顶层也常用 break

 
 
 
 
 
 
 
 
 
posted @ 2025-09-02 14:08  苦逼yw  阅读(229)  评论(0)    收藏  举报