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');
我正在尝试在 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');