Nginx 隐藏式跳转(浏览器 URL 跳转后保持不变)

背景

一个新项目,后端使用 PHP 实现,前端不做路由,提供一个模板,由后端路由控制。

Route::get('pages/{name}', [\App\Http\Controllers\ResourceController::class, 'getResourceVersion']);

当访问路由以 pages/ 开头的路径时,如 http://10.60.10.80/pages/login ,后端返回指定模板。出现一个问题,前端可能会修改浏览器地址,如:http://10.60.10.80/pages/projects/detail?id=1。此时如果用户刷新页面,就会出现 404 问题。

所以当访问类似这种非二级路由的 URL 时,需隐藏式跳转到 pages/ 二级路由,且不改变浏览器地址。可使用修改 Nginx 配置实现。

方案一

将所有 /pages 开头 URI 转发到一个新路由,使用 rewrite break + proxy_pass 实现。

server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /home/workspace/project/pms/public;

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

location ~ /pages {
rewrite ^(/pages).*$ rewrite_pages/login break; # break 跳过当前的 rewrite 阶段(页面不重定向),并继续执行后续的配置
proxy_pass http://10.60.10.80:80; # 以 rewrite_pages/login 为 uri 重新请求 80 端口
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 10.60.10.80:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Route::get('rewrite_pages/{name}', [\App\Http\Controllers\ResourceController::class, 'getResourceVersion']);

方案二

借助 $request_uri,将所有以 /pages 开头的 URI 重新设置为一个固定的二级路由,如 /pages/login。PHP 将读取 REQUEST_URI 变量作为 URI

server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log notice;
access_log /var/log/nginx/access.log;
root /home/workspace/project/pms/public;
rewrite_log on;

set $request_url $request_uri; # 获取 $request_uri 变量,赋值给 $request_url

if ($request_url ~ ^/pages(.*)$ ) {
set $request_url /pages/login; # 设置 $request_url 为 /pages/login。其请求将继续走 location /
}

location / {nginx hidden jump
try_files $uri $uri/ /index.php$is_args$args;
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 10.60.10.80:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REQUEST_URI $request_url; # 注意这里要放在 fastcgi_params 后面,因为 fastcgi_params 中包含 REQUEST_URI 变量
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

参考

Depp Wang wechat
个人公众号