商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > ThinkPHP伪静态规则怎么在Vercel用_ThinkPHPVercel伪静态设置操作【说明】

ThinkPHP伪静态规则怎么在Vercel用_ThinkPHPVercel伪静态设置操作【说明】

  发布于2026-05-21 阅读(0)

扫一扫,手机访问

在Vercel上部署ThinkPHP应用,伪静态规则总返回404,这几乎是每个开发者都会踩的坑。核心原因很明确:Vercel的Serverless环境与传统Apache/Nginx服务器有本质区别,它不支持.htaccess或nginx.conf里的重写规则,并且默认会截断REQUEST_URI,导致ThinkPHP赖以解析路由的PATH_INFO为空。

ThinkPHP伪静态规则怎么在Vercel用_ThinkPHPVercel伪静态设置操作【说明】

所以,一个必须牢记的结论是:直接把Apache或Nginx的rewrite规则搬过来是行不通的。Vercel的重写机制完全由项目根目录的vercel.json文件驱动。而ThinkPHP的PATHINFO模式,恰恰依赖$_SERVER['PATH_INFO']$_SERVER['REQUEST_URI']来获取路由信息。问题就出在这里——Vercel默认不会将完整的原始请求路径透传给PHP运行时,尤其是在使用Build Output API的边缘函数场景下,路径信息在传递过程中就被“吃掉”了。

为什么 Vercel 上 ThinkPHP 伪静态总 404?

我们来拆解一下这个技术黑盒。Vercel的PHP支持基于Serverless Functions(比如@vercel/php运行时),它会把HTTP请求映射为标准CGI环境变量。但在这个过程中,它可能会对REQUEST_URI进行截断或标准化处理。

举个例子,用户访问/user/profile/123,但到了PHP这里,$_SERVER['REQUEST_URI']可能只剩下/index.php,后面的路径参数全丢了。这样一来,ThinkPHP的路由系统自然就收不到s=/user/profile/123/user/profile/123这样的原始路径信息,不返回404才怪。

  • 你熟悉的Apache规则RewriteRule ^(.*)$ index.php/$1在Vercel上完全无效,因为它根本没有mod_rewrite模块。
  • 同样,Nginx配置里的if (!-e $request_filename) { ... }判断文件是否存在再重写,Vercel也根本不解析。
  • 结果就是,ThinkPHP默认的URL_MODEL=2(PATHINFO模式)在Vercel环境下大概率会失效,$_SERVER['PATH_INFO']经常为空或不可靠。

必须改用 URL_MODEL=3(兼容模式) + vercel.json 重写

那么,出路在哪里?答案是切换ThinkPHP的URL模式。从ThinkPHP 5.1+开始,支持URL_MODEL=3,也就是“兼容模式”。这个模式的聪明之处在于,它把路由参数全部放在查询字符串(query string)里传递,比如/index.php?s=/user/profile/123

这种结构对Vercel非常友好,因为查询字符串是HTTP标准的一部分,会被完整地保留并透传给PHP的$_GET全局变量。

  • 首先,在ThinkPHP的配置文件config/app.php中,将'url_model'的值设置为3(记住,不是2)。
  • 确保你的入口文件是public/index.php,并且已经开启了路由功能:'url_route_on' => true
  • 一个关键的实践是:项目内所有链接的生成,都必须使用ThinkPHP的url()助手函数,避免手写硬编码的路径,这样才能保证生成的URL符合兼容模式的格式。

vercel.json 里怎么写重写规则?

模式切换了,接下来就是告诉Vercel如何转发请求。我们的目标是:把所有非静态资源的请求(例如/user/profile/123),都转发到public/index.php这个入口文件,并且附带上s=参数。

这里有个细节需要注意:Vercel的rewrite规则不支持像Nginx那样在destination里直接使用正则捕获组变量(比如$1)。我们需要通过query字段来手动拼接参数。

{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/public/index.php",
      "query": {
        "s": "/$1"
      }
    }
  ]
}
  • source: "/(.*)" 会匹配所有路径(包括根路径/)。不过,Vercel会优先匹配真实存在的静态文件(比如/css/app.css),所以你要确保public/目录下有对应的静态资源。
  • destination 必须指向实际的PHP入口文件路径,即/public/index.php,不能简写成index.php或使用相对路径。
  • query.s 是整个规则的核心。ThinkPHP在兼容模式下,会从$_GET['s']中解析路由,不再依赖PATH_INFO
  • 不要在规则中添加has条件(比如判断文件是否存在)。Vercel的文件存在性检查发生在边缘网络层,PHP运行时无法感知,添加这类条件反而可能干扰重写逻辑。

常见踩坑点:public 目录结构 & build 输出

配置写对了,但部署还是失败?问题可能出在项目结构和构建输出上。Vercel在构建时,默认将整个项目根目录作为Web根目录。但ThinkPHP的标准结构要求Web入口必须在public/子目录下。如果不做处理,index.php可能会找不到框架的核心文件或配置文件。

  • vercel.json中,通过"builds"字段显式指定PHP入口文件:
    "builds": [
      {
        "src": "public/index.php",
        "use": "@vercel/php"
      }
    ]
  • 确保public/目录下包含了完整的ThinkPHP引导文件(如index.php, .htaccess等)。而vendor/thinkphp/框架目录应该通过Composer安装在项目根目录,由public/index.php正确引用。
  • 不要把.env这类环境配置文件放到public/目录下,这有安全风险。Vercel的环境变量应该通过其项目设置面板进行配置。
  • 如果你的项目部署在子目录下(例如https://yourdomain.com/blog/xxx),那么vercel.json中的source规则需要带上前缀:"source": "/blog/(.*)"。同时,别忘了在ThinkPHP的配置中设置'url_domain_root' => '/blog'

最后,一个最容易被忽略的要点是:Vercel的PHP运行时不会自动设置PATH_INFO。这意味着,即便你强行使用URL_MODEL=2,并试图在vercel.json里模拟出PATH_INFO,也很可能因为环境差异而失败。因此,直接切换到URL_MODEL=3是当前最稳定、最可靠的解决方案,别再跟PATHINFO较劲了。

本文转载于:https://www.php.cn/faq/2443252.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注