应优先检查 $_server['http_x_forwarded_proto'] === 'https',启用trustproxy中间件使isssl()准确,并在nginx层做301跳转更高效可靠。

ThinkPHP 5.1+ 中间件里判断 $_SERVER['HTTPS'] 不可靠
直接读 $_SERVER['HTTPS'] 在 Nginx + PHP-FPM 或负载均衡后经常为空或为 off,哪怕实际是 HTTPS 请求。因为反向代理(如 Nginx、SLB、CDN)没把协议头透传给 PHP。
实操建议:
- 优先检查
$_SERVER['HTTP_X_FORWARDED_PROTO']是否等于https,这是绝大多数代理默认透传的字段 - 若用阿里云 SLB 或腾讯云 CLB,确认已开启「传递客户端真实协议」选项(对应 Header 是
X-Forwarded-Proto) - 在中间件中别只依赖
$_SERVER['HTTPS'] === 'on',它在 CGI/FastCGI 环境下基本失效
全局强制跳转用 think\middleware\TrustProxy 配合重定向中间件
ThinkPHP 自带的 TrustProxy 中间件不是用来跳转的,而是让框架信任代理传来的 X-Forwarded-* 头,从而让 Request::isSsl() 返回正确值。必须先启用它,后续跳转逻辑才可靠。
实操建议:
- 在
app/middleware.php中注册think\middleware\TrustProxy::class - 自定义一个中间件(如
HttpsRedirect),在handle()里调用$request->isSsl() ? null : $response->redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], 301) - 确保该中间件放在
TrustProxy之后执行,否则isSsl()仍会误判
url() 生成链接时默认不带 HTTPS 协议
即使全站已强制 HTTPS,url('index/index') 仍可能输出 http:// 开头的地址——因为 ThinkPHP 默认根据当前请求协议生成 URL,而跳转中间件是响应阶段做的事,URL 构建发生在响应前。
实操建议:
- 在
config/app.php中设置'url_common_param' => false并添加'url_domain_root' => 'https://yourdomain.com' - 更稳妥的方式:重写
UrlBuild类,在build()方法里强制替换协议头,或统一用Url::build(..., [], true)的第三个参数强制 HTTPS - 模板中避免裸写
{:url('index/index')},改用{:url('index/index', [], true)}
Nginx 配置比 PHP 层跳转更高效且防绕过
PHP 层跳转依赖代码执行,存在被绕过可能(比如直接访问 index.php 而不走路由),且多一次 PHP 解析开销。Nginx 原生 301 跳转无性能损耗,也无需担心中间件顺序或代理头漏配。
实操建议:
- 在站点 server 块中加:
if ($scheme = 'http') { return 301 https://$host$request_uri; } - 注意不要和
try_files冲突;若用了fastcgi_param HTTPS on;,需同步删掉,否则 PHP 层会误以为自己跑在 HTTPS 下 - 本地开发环境(如 Valet、XAMPP)不适用此法,此时必须回退到 PHP 中间件方案
真正麻烦的是混合部署场景:比如前端 CDN 终止 HTTPS,后端 Nginx 只收 HTTP,这时所有判断都得依赖 X-Forwarded-Proto,且 Nginx 和 PHP 两层配置要对齐,差一个 header 就会循环跳转或降级。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










