Laravel 不自动处理 HTTP→HTTPS 跳转,需由 Web 服务器(Nginx/Apache)或中间件(如 RedirectIfHttps)实现;TrustProxies 必须正确配置以识别 HTTPS;APP_URL 错误、CDN 头未透传、前端资源硬编码 HTTP 均会导致混合内容或跳转失效。

为什么 APP_URL 设为 https:// 还不跳转
因为 Laravel 本身不主动处理 HTTP → HTTPS 重定向,它只信任你告诉它的协议。哪怕 APP_URL 是 https://example.com,Nginx/Apache 收到 HTTP 请求后,Laravel 根本不会“自己发起一次跳转”——它只是照常响应,只是生成的 URL(比如 url()、route())会用 HTTPS。
真正强制跳转必须由 Web 服务器或中间件完成。常见错误是只改了配置,却没动服务器规则或没启用中间件。
- Cloudflare 或反向代理后,
$_SERVER['HTTPS']可能始终为off,导致TrustProxies中间件失效 -
APP_URL写错(比如漏掉https://或带尾部斜杠)会影响资产链接和重定向目标 - 本地开发用 Valet/MailHog 等工具时,HTTP 端口未关闭,浏览器缓存 301 跳转会卡死调试
Laravel 中间件强制 HTTPS 的写法和限制
在 app/Http/Middleware/TrustProxies.php 中,必须明确设置可信代理 IP,并开启协议检测;否则 $request->secure() 永远返回 false。
然后在 app/Http/Middleware/RedirectIfHttps.php(需手动创建)里写:
public function handle($request, Closure $next)
{
if (!$request->secure() && app()->environment('production')) {
return redirect()->secure($request->getRequestUri());
}
return $next($request);
}
再在 app/Http/Kernel.php 的 $middleware 数组里加上它(注意顺序:要放在 TrustProxies 之后)。
- 别在
local环境启用,否则本地php artisan serve会无限跳转 -
redirect()->secure()不会保留查询参数?错,它默认保留;但如果你手动拼接 URL,就容易丢$request->getQueryString() - API 路由通常不该跳转,建议只对
web中间件组生效,避免干扰移动端或 Postman 调试
Nginx/Apache 必须做的底层跳转(比 PHP 层更可靠)
Web 服务器层跳转更快、更早,且绕过 Laravel 生命周期,不受中间件顺序或环境判断影响。这是生产环境首选方式。
Nginx 配置片段(放在 HTTP server 块内):
return 301 https://$host$request_uri;
Apache 的 .htaccess(仅限 DocumentRoot 启用 mod_rewrite):
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
- 确保证书已正确加载,否则跳转后页面直接报
NET::ERR_CERT_INVALID - 如果用了 CDN 或负载均衡,检查
X-Forwarded-Proto头是否透传,Nginx 需加proxy_set_header X-Forwarded-Proto $scheme; - 跳转状态码必须用
301(永久),别用302,否则搜索引擎可能索引两个版本
混合内容(Mixed Content)错误怎么快速定位
浏览器控制台报 Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...',说明前端资源(JS/CSS/图片/iframe)仍用 HTTP 加载。
不是 Laravel 配置问题,而是硬编码或配置残留:
- Blade 模板里写了
<img src="http://cdn.example.com/...">—— 改成协议相对路径//cdn.example.com/...或用{{ asset('...') }} -
ASSET_URL在.env里设成了http://,而APP_URL是https://,两者不一致就会出问题 - 第三方 SDK(如微信 JS-SDK、地图 API)初始化时传了
location.href,而当前页是 HTTP,但跳转后没刷新 SDK 实例
最省事的临时排查法:Chrome 开发者工具 → Security 标签页 → 点 “View certificate”,确认当前页确实是有效 HTTPS;再点 “Mixed Content” 查看具体哪个资源被拦。
HTTPS 不是开关一按就完事的事,从服务器响应头、反向代理设置、Laravel 中间件信任链,到前端资源协议一致性,任何一环松动都会让锁形同虚设。


















