在 nginx 中,`rewrite` 配合 `fastcgi_pass` 传递重写后的脚本路径,核心在于利用 `last` 标志触发内部重定向,使请求重新进入 uri 匹配阶段,从而更新 `$fastcgi_script_name` 变量。具体做法是:在 `location /` 或特定前缀中使用 `rewrite ^/old/(.*)$ /new/$1 last;`,将旧路径映射到新路径,并确保该规则位于 `try_files` 或 `fastcgi_pass` 之前。这样 nginx 会拦截请求,修改内部 uri,然后重新查找匹配的 `location ~ \.php$` 块,最终通过 `fastcgi_pass` 将修正后的 `$fastcgi_script_name` 传递给 php-fpm。

如何配置 rewrite 规则以改变 fastcgi 接收的脚本名
要实现这一功能,必须在处理静态文件或执行 FastCGI 转发之前介入请求流。关键在于使用 `last` 而非 `break`,因为 `break` 仅在当前 location 内停止重写并继续后续指令,不会重置 URI;而 `last` 会终止当前轮询,启动新的 URI 匹配循环,从而让后续的 `location ~ \.php$` 能够捕获到被重写后的新路径。例如,若希望将所有 `/api/v1/user` 的请求转发给 `/index.php` 处理,需配置如下规则。

server {
listen 80;
server_name example.com;
# 定义 API 路由重写
location /api/ {
# 将 /api/v1/resource 重写为 /index.php
# last 标志确保 URI 被更新后重新匹配 location
rewrite ^/api/(.*)$ /index.php last;
}
# 处理 PHP 文件
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
在上述配置中,当请求 `/api/v1/resource` 到达时,首先匹配 `location /api/`。`rewrite` 指令将内部 URI 修改为 `/index.php`,并因 `last` 标志触发重新匹配。此时,请求不再匹配 `/api/`,而是匹配 `location ~ \.php$`。在该 location 中,`$fastcgi_script_name` 变量的值变为 `index.php`,因此 PHP-FPM 接收到的是对 `index.php` 的执行请求,而非原始的 `/api/v1/resource`。这允许后端应用统一入口处理所有 API 请求。
如何处理重写后路径与物理文件不存在的冲突
当 `rewrite` 将请求指向一个并不存在的物理 PHP 文件时,Nginx 默认行为可能导致 404 错误,除非正确配置了 `try_files` 或确保重写目标始终指向存在的主入口。常见误区是直接重写到一个不存在的 `.php` 文件,如 `rewrite ^/old$ /new/script.php last;`,若 `/new/script.php` 不存在,FastCGI 模块可能无法正确处理。更稳健的做法是将所有非静态资源请求重定向到单一入口文件(如 `index.php`),并在 PHP 代码中解析原始 URI。此外,需注意 `$fastcgi_script_name` 的值取决于重写后的 URI,若重写规则复杂,需验证最终传递给 FastCGI 的路径是否正确。

server {
listen 80;
server_name example.com;
root /var/www/html;
# 通用重写规则:将任何非静态文件请求导向 index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 显式处理 PHP
location ~ \.php$ {
# 确保脚本文件存在,避免 404
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
在此配置中,`location /` 中的 `try_files` 指令首先检查请求的 URI 是否对应物理文件或目录。若不存在,则内部重定向至 `/index.php?$query_string`。由于这是内部重定向,URI 变为 `/index.php`,随后匹配 `location ~ \.php$`。在 PHP location 中,`try_files $uri =404;` 再次确认 `index.php` 存在,若存在则继续执行 FastCGI 传递。此时 `$fastcgi_script_name` 为 `index.php`,`$document_root` 为 `/var/www/html`,因此 `SCRIPT_FILENAME` 参数为 `/var/www/html/index.php`,成功传递给 PHP-FPM。这种方法避免了直接重写至不存在文件的 404 问题,同时保持了 URL 的简洁性。
当重写规则包含查询字符串时 fastcgi 如何获取参数
在 `rewrite` 指令中,若未明确指定保留查询字符串,Nginx 默认会附加原始查询字符串到重写后的 URI。这意味着即使脚本路径被重写,GET 参数仍可通过 `$_GET` 在 PHP 中访问。然而,若重写规则中使用了 `?` 截断查询字符串,或手动构建了新 URI 而未包含 `?query_string`,则参数将丢失。为确保 FastCGI 正确接收参数,应检查 `rewrite` 指令是否隐含保留了 `$args`。例如,`rewrite ^/old/(.*)$ /new/$1 last;` 会自动附加原始查询字符串,而 `rewrite ^/old/(.*)$ /new/$1? last;` 则会清除它。开发者需根据业务需求选择是否保留参数,并在 PHP 端通过 `$_SERVER['QUERY_STRING']` 或 `$_GET` 验证参数传递情况。











