必须在Web服务器层(Nginx/Apache)配置HTTPS强制跳转,因Laravel中间件无法安全可靠实现全站重定向:明文传输敏感数据、302跳转影响SEO、无法覆盖API/静态资源、不解决混合内容、Secure Cookie判断不可靠;Nginx应配置独立80端口server块return 301,并在Laravel中启用forceScheme、trustedProxies及secure cookie。

必须在 Web 服务器层(Nginx / Apache)配置 HTTPS 强制跳转,Laravel 应用层无法安全、可靠地实现全站 HTTPS 强制重定向。
为什么不能靠 Laravel 中间件做 301 跳转
应用层跳转存在多个致命缺陷:
- HTTP 请求已进入 PHP 生命周期,敏感数据(如密码、CSRF token)可能已在明文连接中传输
- 中间件跳转是 302 临时重定向,搜索引擎可能不更新索引;手动写 301 又无法覆盖所有入口(API、静态资源、预检请求)
- 混合内容(Mixed Content)问题仍会发生:前端硬编码的
http://链接不会被中间件改写 - Session/Cookie 的
secure属性依赖于服务器实际协议,仅靠$_SERVER['HTTPS']判断不可靠(尤其在反向代理后)
Nginx 下强制 HTTPS 的标准配置
在站点 server 块中添加独立的 HTTP server,并使用 return 301(比 rewrite 更高效):
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# 其他 Laravel 配置(root、index、try_files 等)
root /var/www/laravel/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}}
注意:$server_name 会保留原始 Host,避免多域名时跳转错误;$request_uri 完整保留路径和查询参数。
Laravel 应用内需同步调整的几处关键配置
Web 服务器完成跳转后,Laravel 必须信任代理头并启用安全特性:
- 在
AppServiceProvider::boot()中添加:if ($this->app->environment('production')) { \URL::forceScheme('https'); \Illuminate\Http\Request::setTrustedProxies( ['127.0.0.1', $this->app['request']->server('REMOTE_ADDR')], \Illuminate\Http\Request::HEADER_X_FORWARDED_ALL ); } - 确保
config/session.php中'secure' => env('SESSION_SECURE_COOKIE', true),并在.env设置SESSION_SECURE_COOKIE=true - 设置
config/app.php中'url' => env('APP_URL', 'https://example.com'),且.env的APP_URL必须为https开头 - 生成 URL 时统一用
route()、url()、asset(),避免硬编码http://
最易忽略的是:即使 Nginx 已跳转,若未调用 \URL::forceScheme('https') 或未正确设置 trusted_proxies,Laravel 仍可能生成 http:// 链接,导致前端加载失败或 CSRF 失效。代理环境下的协议判断永远以 X-Forwarded-Proto 为准,而不是 $_SERVER['HTTPS']。










