NGINX配置:如何仅将单个URL重定向至目标URL而不影响子路径?
问题描述
我有地址 https://www.example.com/catalog,希望通过 https://www.example.com/products 访问它。但当前配置重定向后,访问以下子路径时:
https://www.example.com/products/bicycle https://www.example.com/products/car https://www.example.com/products/tshirt ...
都会被重定向回 https://www.example.com/products。
如何仅将 www.example.com/catalog 重定向至 www.example.com/products?
我试过这些配置:
location /products/ { return 301 /catalog/; }
还有:
rewrite /products/ /catalog/ permanent;
以及:
if ($is_args = '') { rewrite ^/catalog\$ /products permanent; }
这些配置能实现从 /products/ 到 /catalog/ 的重定向,但访问 /products/car、/products/tshirt 等子路径时也会被转至 /catalog,不是我要的效果。
我的Nginx配置文件如下:
server { server_name sub.url.ru; root /home/suburl/public_html/; index index.php; access_log /home/sportmen/sportmen.ru/logs/access.log; error_log /home/sportmen/sportmen.ru/logs/error.log; location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_intercept_errors on; } if ($request_uri ~ ^(.*)/index.(html|php)) { return 301 $1/$is_args$args; } location / { try_files $uri $uri/ /bitrix/urlrewrite.php$is_args$args; } location ~* @.*\.html$ { internal; } include /etc/nginx/vhosts-includes/suburl/redirect.conf; listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/suburl/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/suburl/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot ###phpMyadmin### location /phpmy123 { alias /usr/share/phpmyadmin; location ~ \.php$ { fastcgi_pass unix:/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $request_filename; include fastcgi_params; fastcgi_ignore_client_abort off; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { access_log off; log_not_found off; expires 1M; } } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ###end-phpMyAdmin### server { if ($host = sub.url.ru) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; server_name sub.url.ru; return 404; # managed by Certbot }
解决方案
你需要精确匹配根路径,避免影响子路径,以下两种方式都能实现需求:
方式1:使用精确匹配location
把以下配置写入 /etc/nginx/vhosts-includes/suburl/redirect.conf(或放在主配置的include该行之前):
# 精确匹配 /catalog 路径(带/不带末尾斜杠),重定向到 /products location = /catalog { return 301 /products; } location = /catalog/ { return 301 /products/; } # 让 /products 路径转发到 /catalog 的内容 location = /products { try_files $uri $uri/ /catalog; } location = /products/ { try_files $uri $uri/ /catalog/; }
解释:=符号表示精确匹配,只有当请求路径完全等于/catalog或/catalog/时才触发重定向,不会干扰/products/bicycle这类子路径的访问。
方式2:使用rewrite精确匹配
如果更习惯用rewrite规则,可添加:
# 精确匹配 /catalog(无参数)重定向到 /products rewrite ^/catalog$ /products permanent; # 精确匹配 /catalog/(无参数)重定向到 /products/ rewrite ^/catalog/$ /products/ permanent; # 处理/products路径的内容转发 rewrite ^/products$ /catalog last; rewrite ^/products/$ /catalog/ last;
这里的^和$是正则的开始/结束标记,确保只匹配根路径,不会覆盖子路径。
为什么之前的配置失效?
- 你之前的
location /products/是前缀匹配,所有以/products/开头的路径都会被匹配,包括子路径; - 第三个配置只处理了
/catalog到/products的重定向,但没配置/products路径的内容转发逻辑,导致子路径访问时被其他规则干扰。
生效步骤
添加完规则后,重启Nginx使配置生效:
sudo systemctl restart nginx
内容的提问来源于stack exchange,提问作者Alexander_milk_pineapple
相关产品推荐
相关产品推荐

