Laravel 5.4共享主机多标签页redirect back异常问题求助
嘿,我正好碰到过类似的Laravel 5.4在共享主机上的重定向坑,给你几个不用给每个表单硬编码固定URL的解决方案!
问题根源再确认
你已经排查到关键点了:共享主机环境丢失了HTTP_REFERER请求头,Laravel只能 fallback 用session里的_previous.url值,但多标签页打开新页面时会覆盖这个session值,导致验证失败/redirect()->back()时跳去了新标签页的URL,而非表单所在的编辑页。
下面是几个可行的解决思路:
方案1:用隐藏字段记录表单来源URL(最直观易实现)
这个方法的核心是在表单页面加载时,把当前URL存入表单的隐藏字段,验证失败时直接重定向到这个字段的值,完全绕开session和referer的问题。
步骤:
创建中间件,给表单页面共享当前URL
生成一个中间件:php artisan make:middleware RecordFormOrigin打开
app/Http/Middleware/RecordFormOrigin.php,修改handle方法:public function handle($request, Closure $next) { // 匹配你的表单路由,比如产品编辑、创建,分类编辑等 $formRoutes = [ 'products/*/edit', 'products/create', 'categories/*/edit', 'categories/create' ]; foreach ($formRoutes as $route) { if ($request->is($route)) { // 把当前完整URL共享给视图 view()->share('form_origin', $request->fullUrl()); break; } } return $next($request); }然后在
app/Http/Kernel.php的web中间件组里注册这个中间件:protected $middlewareGroups = [ 'web' => [ // 其他中间件... \App\Http\Middleware\RecordFormOrigin::class, ], // ... ];在表单里添加隐藏字段
所有需要正确重定向的表单里,加上这个隐藏字段:@isset($form_origin) <input type="hidden" name="_origin" value="{{ $form_origin }}"> @endisset修改验证失败的重定向逻辑
- 如果用Form Request验证:在你的FormRequest类里重写
failedValidation方法:use Illuminate\Validation\ValidationException; use Illuminate\Contracts\Validation\Validator; protected function failedValidation(Validator $validator) { // 优先取隐藏字段的来源URL,再fallback到默认逻辑 $originUrl = $this->input('_origin', url()->previous()); throw (new ValidationException($validator)) ->errorBag($this->errorBag) ->redirectTo($originUrl); } - 如果用控制器里的
$request->validate():用try-catch捕获验证异常,手动重定向:try { $validatedData = $request->validate([ 'name' => 'required|max:10', // 其他验证规则 ]); } catch (ValidationException $e) { return redirect($request->input('_origin', url()->previous())) ->withErrors($e->errors()) ->withInput(); }
- 如果用Form Request验证:在你的FormRequest类里重写
方案2:全局扩展url()->previous()方法(一劳永逸)
如果你不想逐个修改验证逻辑,可以扩展Laravel的URL生成器,让url()->previous()优先读取表单里的_origin隐藏字段,这样不管是redirect()->back()还是验证失败的自动重定向,都会用正确的来源URL。
步骤:
创建自定义URL生成器
在app/Providers目录下新建CustomUrlGenerator.php:namespace App\Providers; use Illuminate\Http\Request; use Illuminate\Routing\UrlGenerator as BaseUrlGenerator; class CustomUrlGenerator extends BaseUrlGenerator { public function previous($fallback = null) { $request = $this->request; // 优先取请求里的_origin参数 if ($request && $origin = $request->input('_origin')) { return $origin; } // 没有的话再用默认逻辑 return parent::previous($fallback); } }在服务提供者里替换默认的URL生成器
打开app/Providers/AppServiceProvider.php,在register方法里添加:public function register() { $this->app->bind('url', function ($app) { $routes = $app['router']->getRoutes(); $url = new CustomUrlGenerator( $routes, $app->rebinding('request', function ($app, $request) { $app['url']->setRequest($request); }) ); $url->setSessionResolver(function () { return $this->app['session'] ?? null; }); return $url; }); }给表单添加隐藏字段
和方案1一样,在表单里加上_origin隐藏字段即可,之后所有的redirect()->back()和验证失败重定向都会自动优先用这个值。
方案3:尝试修复共享主机的HTTP_REFERER头(可选)
有些共享主机可能因为安全配置或CDN的原因,移除了HTTP_REFERER头,你可以试试在.htaccess文件里添加以下配置(如果是Apache服务器):
RewriteEngine On RewriteCond %{HTTP_REFERER} !^$ RewriteRule ^(.*)$ - [E=HTTP_REFERER:%{HTTP_REFERER}]
如果是Nginx服务器,需要在主机配置里添加:
proxy_set_header Referer $http_referer;
不过共享主机通常不让修改Nginx配置,所以这个方法优先级最低,先试试前面两个方案。
内容的提问来源于stack exchange,提问作者twis

