You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将.htaccess转Nginx配置时,/cms路径跳转及访问异常问题排查

.htaccess转Nginx配置:CMS路径问题修复

问题现状

  • 前端站点从/frontend/public目录提供服务,运行正常
  • 后台CMS站点从/backend/public目录提供服务时存在两个问题:
    1. 访问/cms会自动重定向到/cms/login,但Nginx返回404错误
    2. 移除登录验证后访问/cms,页面可正常显示,但浏览器URL会自动变为/backend/public

当前Nginx配置

server {
  listen 80;

  root /home/anon/web/project;

  index index.php index.html index.htm index.nginx-debian.html;

  server_name project.test;

  location ~ ^/cms$ {
    rewrite ^(.*)$ /cms/ redirect;
  }

  location /cms {
    rewrite ^/cms(.*)$ /backend/public/$1 last;
  }

  location /backend/public {
    if (!-e $request_filename) {
      rewrite ^(.*)$ /index.php;
    }
  }

  location / {
    if (!-e $request_filename) {
      rewrite ^/(.*)/$ /$1 redirect;
    }

    if (!-e $request_filename) {
      rewrite ^(.+)$ /frontend/public/$1 break;
    }

    rewrite ^/[a-zA-Z0-9_/\-'"$]*$ /frontend/public/index.php last;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    fastcgi_buffering off;
  }
}

待转换的.htaccess文件

Options -Indexes
RewriteEngine on

RedirectMatch 301 ^/cms$ /cms/

RewriteRule ^cms(.*)$ backend/public/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/frontend/public/%{REQUEST_URI} -f
RewriteRule ^(.+)$ frontend/public/$1 [L]

RewriteRule ^[a-zA-Z0-9_/\-'"$]*$ frontend/public/index.php [L]

问题分析与修正方案

核心错误点

  1. CMS路由重写目标错误:原配置中/backend/public下的不存在请求被重写到根目录/index.php,但CMS的入口文件实际是/backend/public/index.php,导致404。
  2. URL暴露真实路径:原规则没有确保内部重写的隐蔽性,应用可能检测到真实路径后触发跳转,导致地址栏变为/backend/public。
  3. 过多使用if语句:Nginx中if容易引发规则冲突,推荐用try_files和命名location替代。

修正后的Nginx配置

server {
  listen 80;

  root /home/anon/web/project;

  index index.php index.html index.htm index.nginx-debian.html;

  server_name project.test;

  # 匹配不带斜杠的/cms,重定向到带斜杠版本(对应原htaccess的RedirectMatch)
  location = /cms {
    return 301 /cms/;
  }

  # 优先匹配/cms开头的请求,内部重写到backend/public(用last触发重新匹配)
  location ^~ /cms {
    rewrite ^/cms(.*)$ /backend/public$1 last;
  }

  # 处理backend/public下的静态文件与路由,直接指向CMS入口文件
  location /backend/public {
    try_files $uri $uri/ /backend/public/index.php$is_args$args;
  }

  # 前端站点基础处理
  location / {
    # 移除非目录请求的末尾斜杠
    if (!-d $request_filename) {
      rewrite ^/(.*)/$ /$1 permanent;
    }
    # 先尝试静态文件,不存在则转交给@frontend处理
    try_files $uri $uri/ @frontend;
  }

  # 前端路由与静态文件映射规则
  location @frontend {
    # 检查前端目录是否存在该文件,存在则重写过去
    if (-f $document_root/frontend/public$uri) {
      rewrite ^(.+)$ /frontend/public$1 last;
    }
    # 否则重写到前端入口文件
    rewrite ^ /frontend/public/index.php last;
  }

  # PHP脚本处理,确保路径参数正确
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    fastcgi_buffering off;
    # 修正SCRIPT_FILENAME参数,避免重写后的路径错误
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    fastcgi_param DOCUMENT_ROOT $realpath_root;
  }
}

修正说明

  • 用location = /cms精准匹配单一路径,return 301比rewrite更高效。
  • location ^~ /cms使用^~前缀确保优先匹配,避免被其他规则干扰,内部重写后用last让Nginx重新匹配对应的/backend/public规则。
  • location /backend/public改用try_files处理静态文件和路由,直接指向CMS入口文件,解决404问题。
  • 前端部分重构为try_files+命名location,替代原有的多个if语句,减少规则冲突风险。
  • PHP块添加fastcgi_param修正脚本路径参数,确保PHP能正确找到重写后的脚本文件。

内容的提问来源于stack exchange,提问作者altpotato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:11:07