Laravel 本地化中间件导致 ERR_TOO_MANY_REDIRECTS

Laravel localization middleware causing ERR_TOO_MANY_REDIRECTS

我正在尝试在 laravel 应用程序中设置本地化,但我的中间件似乎导致 ERR_TOO_MANY_REDIRECTS 错误。该网站将因地区而略有不同,我正在使用 laravel lang/ 文件来换出 phone 号码等。这没问题。当我更改语言环境时,我会从 lang 文件中获得正确的数字。当我只有中间件来检查是否已将 cookie 设置为设置有效的语言环境时。

我还有中间件可以忘记本地化路由的前缀,这样我就不必使用语言环境参数更新我的方法。

如果在我的中间件中使用允许的语言环境设置了 cookie,我的问题是设置 url 前缀。如果语言环境是 'en',我也想忽略前缀,因为它将是默认的。

下面是所有的代码

routes/web.php

Route::get('/', 'HomeController@index')->name('home');
Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');

Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
    Route::get('/', 'HomeController@index')->name('home');
    Route::middleware('forget.prefix')->get('/reader/{identifier}', 'ReaderController@show')->name('reader');
});

Middleware/Localization.php - 添加到 Kernel.php 中的 web 中间件组。它检查 cookie 并设置语言环境,并且应该重定向到正确的语言环境前缀。如果没有设置 cookie,那么我们获取用户地理位置并设置它。

public function handle($request, Closure $next)
{
    // Get requested url
    $segments = collect($request->segments());

    if ($segments->count() && Arr::exists(config('app.allowed_locales'), $segments[0])) {
        $segments->shift();
    }

    $locale = Cookie::get('locale');

    if ($locale ?? false) {
        // Set the app locale.
        App::setLocale($locale);

        if ($locale != 'en') {
            $segments->prepend($locale);
            return redirect()->to($segments->implode('/'));
        }
    } else {
        // Check for geo here and set it.
    }

    return $next($request);
}

Middleware/RedirectLocalization.php - 这个中间件只在前缀的路由组上设置。它检查是否允许传递的语言环境并设置语言环境和 cookie。这是在 Kernel.php

中的 $routeMiddleware 数组中设置的
public function handle($request, Closure $next)
{
    $locale = $request->segment(1);

    if (Arr::exists(config('app.allowed_locales'), $locale)) {
        // Set the app locale.
        App::setLocale($locale);

        // Save app locale in a Cookie.
        Cookie::queue(Cookie::make('locale', $locale, 525600));
    }

    return $next($request);
}

Controllers/SetLocaleController.php - 这是可以从网站上的菜单手动设置语言环境的地方。

public function __invoke($locale, Request $request)
{
    $redirectUrl = parse_url(url()->previous());
    $segments = Str::of($redirectUrl['path'])->trim('/')->explode('/');

    if (Arr::exists(config('app.allowed_locales'), $segments[0])) {
        $segments->shift();
    }

    if (Arr::exists(config('app.allowed_locales'), $locale)) {
        // Set the app locale.
        App::setLocale($locale);

        // Save app locale in a Cookie.
        Cookie::queue(Cookie::make('locale', $locale, 525600));

        // Add locale to segments for redirect.
        if ($locale != 'en') {
            $segments->prepend($locale);
        }
    } else {
        // Set locale to current locale.
        App::setLocale(config('app.fallback_locale'));
    }

    // Redirect back
    return redirect()->to($segments->implode('/'));
}

Controllers/ReaderController.php - 这里没什么特别的,但我想添加它来解释 forget.prefix 中间件。如果我不添加 forget.prefix 中间件,那么 $reader 参数将成为语言环境。

public function show($reader, Request $request)
{
    $reader = Reader::find($reader);

    return view('readers.show', [
        'reader' => $reader
    ]);
}

Middleware/ForgetPrefix.php - 这个中间件删除了前缀,这样我们就可以访问控制器方法中的参数,而不必向控制器中的方法添加 $locale 参数。

public function handle($request, Closure $next)
{
    $request->route()->forgetParameter('locale');
    
    return $next($request);
}

所以我的问题是,如果已在 cookie 中设置了语言环境,我该如何设置 URL 前缀而不会出现太多重定向错误?

所以我发现我的问题来自将 Middleware/Localization.php 添加到网络中间件组。我将这个中间件添加到 Kernel.php 中的 $routeMiddleware。相反,我只将 Middleware/Localization.php 添加到默认语言环境路由。

我的更新web/routes.php

Route::group(['middleware' => 'localization'], function () {
    Route::get('/', 'HomeController@index')->name('home');
    Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
});

Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
    Route::get('/', 'HomeController@index')->name('home');

    Route::group(['middleware' => 'forget.prefix'], function () {
        Route::get('/reader/{identifier}', 'ReaderController@show')->name('reader');
    });
});

// Switch Locale route
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');