laravel + haproxy + https 后生成分页 url 非 https 解决办法

更合适的解决办法:在 AppServiceProvider boot 方法中使用 \URL::forceScheme('https'); 便可。php

背景

近日对全部的客户都上线了 https ,原本在 beta 环境中是没有任何问题,都测试经过了,可是在正式上线后,发现后台管理系统中的 laravel 分页生成的 url 是非 https 的,可是其余地方(路由,静态资源)等生成的都是正常的 https 连接,遂找缘由解决。laravel

解决

laravel 的分页服务 Illuminate\Pagination\PaginationServiceProvider::class 找到该 ServiceProvider 源码中 register() 中的代码app

Paginator::currentPathResolver(function () {
        return $this->app['request']->url();
});

能够看到分页连接生成的时候,是根据当前请求的 url 来设置分页类的 url path.ide

接着找到 Illuminate\Http\Request::class 中的 url()测试

public function url()
    {
        return rtrim(preg_replace('/\?.*/', '', $this->getUri()), '/');
    }

在这里咱们能够发现 laravel 的 Request 类是继承自 Symfony 的 Request,经过不断地位咱们能够找到以下代码:this

public function isSecure()
    {
        if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
            return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));
        }

        $https = $this->server->get('HTTPS');

        return !empty($https) && 'off' !== strtolower($https);
    }

看到这段源码后,咱们打印了生产环境中的 phpinfourl

clipboard

经过源码对比发现,Symfony 中默认读取的是 X_FORWARDED_PROTO and X_FORWARDED_PORT,可是咱们 php 环境中是 HTTP_X_FORWARDED_PROTO and HTTP_X_FORWARDED_PORT,咱们在源码中发现了以下方法:code

/**
     * Sets the name for trusted headers.
     *
     * The following header keys are supported:
     *
     *  * Request::HEADER_CLIENT_IP:    defaults to X-Forwarded-For   (see getClientIp())
     *  * Request::HEADER_CLIENT_HOST:  defaults to X-Forwarded-Host  (see getHost())
     *  * Request::HEADER_CLIENT_PORT:  defaults to X-Forwarded-Port  (see getPort())
     *  * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure())
     *
     * Setting an empty value allows to disable the trusted header for the given key.
     *
     * @param string $key   The header key
     * @param string $value The header name
     *
     * @throws \InvalidArgumentException
     */
    public static function setTrustedHeaderName($key, $value)
    {
        if (!array_key_exists($key, self::$trustedHeaders)) {
            throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
        }

        self::$trustedHeaders[$key] = $value;
    }

能够发现这是一个静态方法,所以咱们只须要在 AppServiceProvider 中加入以下代码便可server

Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT,'HTTP_X_FORWARDED_PORT');
Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO,'HTTP_X_FORWARDED_PROTO');

讨论交流

讨论交流

相关文章
相关标签/搜索