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

所以,一个必须牢记的结论是:直接把Apache或Nginx的rewrite规则搬过来是行不通的。Vercel的重写机制完全由项目根目录的vercel.json文件驱动。而ThinkPHP的PATHINFO模式,恰恰依赖$_SERVER['PATH_INFO']或$_SERVER['REQUEST_URI']来获取路由信息。问题就出在这里——Vercel默认不会将完整的原始请求路径透传给PHP运行时,尤其是在使用Build Output API的边缘函数场景下,路径信息在传递过程中就被“吃掉”了。
我们来拆解一下这个技术黑盒。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才怪。
RewriteRule ^(.*)$ index.php/$1在Vercel上完全无效,因为它根本没有mod_rewrite模块。if (!-e $request_filename) { ... }判断文件是否存在再重写,Vercel也根本不解析。URL_MODEL=2(PATHINFO模式)在Vercel环境下大概率会失效,$_SERVER['PATH_INFO']经常为空或不可靠。那么,出路在哪里?答案是切换ThinkPHP的URL模式。从ThinkPHP 5.1+开始,支持URL_MODEL=3,也就是“兼容模式”。这个模式的聪明之处在于,它把路由参数全部放在查询字符串(query string)里传递,比如/index.php?s=/user/profile/123。
这种结构对Vercel非常友好,因为查询字符串是HTTP标准的一部分,会被完整地保留并透传给PHP的$_GET全局变量。
config/app.php中,将'url_model'的值设置为3(记住,不是2)。public/index.php,并且已经开启了路由功能:'url_route_on' => true。url()助手函数,避免手写硬编码的路径,这样才能保证生成的URL符合兼容模式的格式。模式切换了,接下来就是告诉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运行时无法感知,添加这类条件反而可能干扰重写逻辑。配置写对了,但部署还是失败?问题可能出在项目结构和构建输出上。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较劲了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8