Laravel и ngrok: домен URL-адреса неверен для маршрутов и активов

Моя установка:

  • Homestead на Mac OSX с несколькими настроенными сайтами
  • У меня есть одна настройка сайта, использующая domfit.test в качестве локального домена (автоматически сопоставленный с помощью hostsupdater)

Моя проблема:

Если я vagrant ssh, а затем share domfit.test, я получу случайно сгенерированный URL-адрес ngrok, как и следовало ожидать (http://whatever.ngrok.io), однако, когда я получаю доступ к этому URL-адресу, все мои ресурсы/маршруты имеют префикс http://domfit.test/ (http://domfit.test/login например)

Я пробовал следующее:

  • Установка APP_URL в качестве URL-адреса ngrok
  • php artisan config:clear
  • php artisan cache:clear
  • {{ url('login') }}
  • {{ route('login') }}

Насколько я понимаю, url() должен возвращать фактический URL-адрес, запрошенный браузером (а не использовать APP_URL), но он всегда возвращает domfit.test.

Если я переименую свой сайт в Homestead.yaml (например, в newdomfit.test) и переназначу, то это будет домен, который используют url() и route(), независимо от моего APP_URL. Таким образом, Homestead.yaml, кажется, форсирует этот домен. Напрашивается вопрос: как вы собираетесь использовать функцию общего доступа?

Я новичок в Laravel, поэтому я не уверен, что все это ожидаемое поведение, и я что-то неправильно понимаю?

Я просто хочу, чтобы мои ссылки и ресурсы в шаблонах работали для локального (domfit.test), общего (ngrok) и, в конечном итоге, для производства с одним и тем же фрагментом кода. Меня беспокоит то, что мне придется изменить все мои route() или url() ссылки, когда я попытаюсь запустить этот веб-сайт.

ИЗМЕНИТЬ НИЖЕ

Хорошо, я только что попробовал еще раз. Заменено APP_URL на ngrok:

Искал всю мою кодовую базу для domfit.test, и только некоторые случайные файлы сеансов, похоже, имеют ссылки:

код/domfit/хранилище/фреймворк/сеансы/

APP_NAME=DomFit
APP_VERSION=0.01
APP_ENV=local
APP_KEY=XXXX
APP_DEBUG=true
APP_URL=http://04b7beec.ngrok.io

Затем в моем контроллере я делаю это для простой отладки:

echo(url('/login'));
echo(route('login'));
echo($_SERVER['HTTP_HOST']);
echo($_SERVER['HTTP_X_ORIGINAL_HOST']);

Если я использую URL-адрес ngrok, я получаю вывод:

http://domfit.test/login
http://domfit.test/login
domfit.test
04b7beec.ngrok.io

Я не понимаю, как $_SERVER['HTTP_HOST'] возвращает неверный URL?

Похоже, это может быть связано с этим: https://github.com/laravel/valet/issues/342

ДРУГОЕ ИЗМЕНЕНИЕ

Похоже, это связано с командой Homestead share:

function share() {
if [[ "$1" ]]
then
    ngrok http ${@:2} -host-header="$1" 80
else
    echo "Error: missing required parameters."
    echo "Usage: "
    echo "  share domain"
    echo "Invocation with extra params passed directly to ngrok"
    echo "  share domain -region=eu -subdomain=test1234"
fi

}

Который передает параметр -host-header в ngrok, который согласно их документации:

Некоторые серверы приложений, такие как WAMP, MAMP и pow, используют заголовок Host для определения того, какой сайт разработки отображать. По этой причине ngrok может переписать ваши запросы с измененным заголовком Host. Используйте переключатель -host-header для перезаписи входящих HTTP-запросов.

Если я использую ngrok без него, то отображаемый веб-сайт будет другим (потому что у меня настроено несколько сайтов в Homestead), поэтому я все еще не знаю, как это обойти. На данный момент я могу отключить другие сайты, так как я не занимаюсь их активной разработкой.


person Dominic Williams    schedule 05.05.2018    source источник
comment
Каково точное значение APP_URL в вашем файле .env? Может быть, даже вставить всю строку.   -  person parker_codes    schedule 06.05.2018
comment
пожалуйста, добавьте свой файл .env   -  person Babak Asadzadeh    schedule 06.05.2018
comment
Просто совет по устранению неполадок, просто найдите domfit.test во всем проекте и посмотрите, где он используется. :)   -  person emotality    schedule 06.05.2018
comment
Я только что обновил исходный вопрос, добавив дополнительную информацию. Любые другие предложения с благодарностью!   -  person Dominic Williams    schedule 06.05.2018
comment
@DominicWilliams У меня точно такая же проблема, вам удалось это исправить?   -  person Helen Che    schedule 12.10.2018
comment
@DominicWilliams Вы когда-нибудь это понимали? У меня такая же проблема. Я не понимаю обсуждения здесь, но оно кажется связанным: github.com/laravel/framework/ вопросы/18613   -  person Ryan    schedule 17.12.2018
comment
@HelenChe Ты понял это?   -  person Ryan    schedule 17.12.2018
comment
@Ryan, к сожалению, нет, и это позор, потому что этот инструмент тестирования почти идеален.   -  person Helen Che    schedule 05.01.2019
comment
@ Райан, я знаю, что вы искали некоторое время назад, но на случай, если вы все еще ищете ответ, я дал его ниже.   -  person patricus    schedule 18.03.2019
comment
@HelenChe Я знаю, что вы искали некоторое время назад, но на случай, если вы все еще ищете ответ, я дал его ниже.   -  person patricus    schedule 18.03.2019
comment
@patricus Спасибо! Я посмотрю на это в следующий раз, когда столкнусь с этой проблемой.   -  person Ryan    schedule 18.03.2019


Ответы (5)


Несмотря на то, что вы переходите по URL-адресу ngrok, заголовок хоста в запросе по-прежнему устанавливается как имя вашего сайта. Laravel использует заголовок хоста для создания абсолютного URL-адреса для ссылок, ресурсов и т. д. ngrok включает URL-адрес ngrok в заголовок X-Original-Host, но Laravel ничего об этом не знает.

Есть два основных решения проблемы:

  1. обновить запрос с правильными значениями сервера и заголовка, или
  2. используйте метод forceRootUrl(), чтобы игнорировать значения сервера и заголовка.

Доверенные прокси-серверы и узел переадресации

Если вы используете TrustedProxies (по умолчанию в Laravel >= 5.5) и у вас настроено доверие ко всем прокси (protected $proxies = '*';), вы можете установить заголовок X-Forwarded-Host в заголовок X-Original-Host. Затем Laravel будет использовать значение в заголовке X-Forwarded-Host для построения всех абсолютных URL-адресов.

Вы можете сделать это на уровне веб-сервера. Например, если вы используете apache, вы можете добавить это в свой файл public/.htaccess:

# Handle ngrok X-Original-Host Header
RewriteCond %{HTTP:X-Original-Host} \.ngrok\.io$ [NC]
RewriteRule .* - [E=HTTP_X_FORWARDED_HOST:%{HTTP:X-Original-Host}]

Если вы предпочитаете обрабатывать это в своем приложении, а не на веб-сервере, вам нужно будет обновить запрос Laravel. Есть много мест, где вы можете сделать это, но одним из примеров может быть ваш метод AppServiceProvider::boot():

public function boot(\Illuminate\Http\Request $request)
{
    if ($request->server->has('HTTP_X_ORIGINAL_HOST')) {
        $request->server->set('HTTP_X_FORWARDED_HOST', $request->server->get('HTTP_X_ORIGINAL_HOST'));
        $request->headers->set('X_FORWARDED_HOST', $request->server->get('HTTP_X_ORIGINAL_HOST'));
    }
}

Не использовать доверенные прокси

Если вы не используете TrustedProxies, вы не можете использовать метод .htaccess. Однако вы по-прежнему можете обновлять значения сервера и заголовков в своем приложении. В этом случае вам нужно перезаписать заголовок Host:

public function boot(\Illuminate\Http\Request $request)
{
    if ($request->server->has('HTTP_X_ORIGINAL_HOST')) {
        $request->server->set('HTTP_HOST', $request->server->get('HTTP_X_ORIGINAL_HOST'));
        $request->headers->set('HOST', $request->server->get('HTTP_X_ORIGINAL_HOST'));
    }
}

Используя forceRootUrl()

Если вы не хотите изменять какие-либо заголовки или запрос Laravel, вы можете просто указать генератору URL-адресов, какой корневой URL-адрес использовать. Генератор URL имеет метод forceRootUrl(), который вы можете использовать, чтобы указать ему использовать конкретное значение вместо просмотра запроса. Опять же, в вашем методе AppServiceProvider::boot():

public function boot(\Illuminate\Http\Request $request)
{
    if ($request->server->has('HTTP_X_ORIGINAL_HOST')) {
        $this->app['url']->forceRootUrl($request->server->get('HTTP_X_FORWARDED_PROTO').'://'.$request->server->get('HTTP_X_ORIGINAL_HOST'));
    }
}
person patricus    schedule 02.02.2019
comment
При использовании Laravel 5.8 без каких-либо изменений работают только два последних метода. Именованный маршрут приводит к http вместо https. - person Rivo; 23.06.2019
comment
Чтобы преодолеть эту проблему http, мне нужно доверять всем прокси, отредактировав файл TrustProxies.php в app\Http\Middleware\. Просто добавьте * к protected $proxy, строка 15. Это редактирование на удивление заставляет работать все методы, описанные patricus. Любые опасения по поводу безопасности всего этого? - person Rivo; 23.06.2019
comment
Лучший ответ когда-либо. - person Faizan Anwer Ali Rupani; 22.01.2020
comment
Лучший ответ когда-либо !! - person rc1021; 01.06.2021
comment
這 回答 最 佳 的 答案。 先 講 作法: 1. 找到 app\Http\Middleware\TrustProxies.php 2. 將 protected $proxies; 改為 protected $proxies = '*'; 因為 route('name') 的 是否 為 https 取決於 Symfony\Component\HttpFoundation\Request 這個 檔案 的 isSecure() , 你 的 是 是 _ 為 檔案 ,那麼你必需將 forward 的 ip 位置加入Proxies 的名單中。 - person rc1021; 01.06.2021

Вы можете принудительно использовать протокол с последним решением @patricus, используя это:

$this->app['url']->forceScheme('https');
person David Martínez    schedule 19.08.2020
comment
Это очень похоже на уже данный ответ. В чем разница? - person marsh-wiggle; 19.08.2020
comment
Его дополняет. Если вы только принудительно используете корень, сгенерированный URL-адрес будет использовать http вместо https, как сказал @Rivo. - person David Martínez; 20.08.2020
comment
Это было полезно и должно быть частью основного ответа ... если вы используете Https локально. - person digout; 31.10.2020

Вот что я придумал для своей проблемы с тегом <base> ngrok:

<base href="{{request()->isSecure() ? 'https' : 'http'}}://{{ $_SERVER['HTTP_X_ORIGINAL_HOST'] ?? request()->getHttpHost() }}">
person Mladen Janjetovic    schedule 01.04.2019

У меня есть аналогичная проблема, и я решил ее, как показано ниже.

В AppServiceProvider.php добавьте ниже проверку внутри boot()

if (!empty( env('NGROK_URL') ) && $request->server->has('HTTP_X_ORIGINAL_HOST')) {
            $this->app['url']->forceRootUrl(env('NGROK_URL'));
        }

Также в .env добавьте запись ниже

NGROK_URL=xxxx.ngrok.io

Полный документ решения (ссылка)

person dev_mustafa    schedule 27.03.2021

В ваших файлах app.config и .env попробуйте изменить его на:

'url' => env('APP_URL', 'http://localhost'),

person CupOfSalt    schedule 06.05.2018