Миграция на Laravel, Vanity URL, промежуточное ПО для всех запросов, проблема с Auth::user и $errors

Я создал класс промежуточного программного обеспечения с именем PathParser, который запускается при каждом запросе. Цель состоит в том, чтобы обрабатывать запросы на «пути URL-адресов тщеславия», которые мы разрешили пользователям создавать в нашем ванильном PHP-приложении до Laravel. Например: пользователь создал URL-адрес, такой как: http://example.com/i-love-this-place

Что делает PathParser, так это проверяет ответы 404, а затем смотрит, соответствует ли путь URL одному из наших старых путей тщеславия. Как это:

class PathParser
{   
    public function handle($request, Closure $next, $guard = null)
    {
        $next_response = $next($request);       
        $status_code = $next_response->getStatusCode();

        if ($status_code === 404) {
            $script_url = $request->server("SCRIPT_URL");

            $vanity_controller = new VanityController();
            $found_vanity_id = Search::findVanityPath($script_url);

            if (!empty($found_vanity_id)) {
                $next_response = response()->make($vanity_controller->one($found_vanity_id));
            }
        }

        return $next_response;
    }
}

Предположим следующее:

  1. Пользователь никогда не создавал путь URL, который конфликтует с каким-либо маршрутом.

  2. Я должен поддерживать ряд существующих (до Laravel) именных URL-адресов, которые находятся в свободном доступе — размещены в социальных сетях и т. д.

В Kernel.php у меня есть следующее:

protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\PathParser::class,
        //\Illuminate\Session\Middleware\StartSession::class,
        //\Illuminate\View\Middleware\ShareErrorsFromSession::class,
    ];

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],    
    ];

В массиве $middleware я попробовал добавить StartSession и ShareErrorsFromSession (раскомментировав 2 строки выше), и это частично работает. Но с двумя основными проблемами:

  • Auth::user имеет значение null, даже для запросов, сделанных к тщеславным путям вошедшими в систему пользователями.
  • $errors больше не заполняется при отправке формы (например, на страницах регистрации и входа), когда пользователь отправляет неверную/недействительную информацию.

Есть ли способ как проверить маршрут для всех запросов, так и получить доступ к аутентифицированному пользователю, а также сохранить $errors?

У меня такое чувство, что я недостаточно хорошо понимаю жизненный цикл запроса, чтобы добиться успеха. Но может есть способ?

Если невозможно сделать то, что мне нужно, используйте перенаправление 302 на стандартизированный путь с префиксом (например, http://example.com/vanity/i-love-this-place) — прекрасное решение. Но я надеюсь, что есть другое средство.


person udog    schedule 23.12.2016    source источник
comment
Есть ли причина, по которой вы не можете добавить PathParser в конец группы промежуточного программного обеспечения web?   -  person patricus    schedule 24.12.2016
comment
Когда я помещаю PathParser в массив веб-промежуточного ПО, любой запрос на тщеславный путь идет прямо на встроенную страницу 404 Laravel и полностью обходит PathParser. На самом деле, кажется, что фреймворк даже не создает экземпляр PathParser — я могу поместить в него неправильный синтаксис и сохранить его, и нет никакого исключения, просто прямо до 404. Но когда я выбираю правильный маршрут, появляется это синтаксическое исключение. И, может быть, это дает нам подсказку - я имею в виду, возможно, есть способ обойти автоматическую обработку 404 в Laravel (что может привести к решению)?   -  person udog    schedule 24.12.2016
comment
Ах, да, это имеет смысл. Сопоставление маршрута выполняется до применения промежуточного программного обеспечения маршрута, поэтому исключение NotFoundHttpException выдается до того, как ваше промежуточное программное обеспечение будет выполнено.   -  person patricus    schedule 24.12.2016


Ответы (1)


Пара предложений:

Если вам не нужны авторизация/сеансы/и т. д., вы можете просто обработать исключение Symfony\Component\HttpKernel\Exception\NotFoundHttpException внутри обработчика исключений вашего приложения.

В app/Exceptions/Handler.php измените метод render(), чтобы он выглядел примерно так:

public function render($request, Exception $e)
{
    if ($e instanceof \Symfony\Component\HttpKernel\Exception\NotFoundHttpException) {
        // your code that returns a Response
    }

    return parent::render($request, Exception $e);
}

Если вам действительно нужны auth/sessions/etc, я бы предложил создать «объединяющий» маршрут в конце вашего файла маршрутов. Например, в качестве самой последней строки в вашем файле routes/web.php поместите:

Route::any('{catchall}', 'VanityController@handle')->where('catchall', '(.*)');

Затем внутри вашего VanityController есть метод handle, который выглядит так:

public function handle(Request $request, $url)
{
    // logic to search and render your vanity page for $url

    // if no vanity page was found:
    throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException();
}
person patricus    schedule 24.12.2016
comment
Это тщательно продуманное решение, и оно отлично заработало, как только я его реализовал — я использовал общий маршрут, но также приятно знать, что я могу выборочно обрабатывать исключения HTTP. - person udog; 26.12.2016