Laravel 5.4使用spatie/pjax插件登录时出现422 Unprocessable Entity错误
我之前也碰到过一模一样的情况,用Spatie的PJAX插件时,点击登录、注册链接这类GET请求都正常,可一提交登录表单就炸出这个422错误。咱们一步步捋清楚怎么解决:
先搞懂问题根源
这个错误是FilterIfPjax中间件里的fetchContainer方法找不到指定的#body容器导致的。当登录表单验证失败时,Laravel会返回登录页面的视图,但PJAX中间件会尝试从这个响应里提取#body区域的内容,如果你的登录视图里没这个容器,或者中间件没正确识别到,就直接抛出422错误了。
解决方案一:给登录视图补上#body容器
打开你的登录视图文件(一般是resources/views/auth/login.blade.php),检查主内容是不是包裹在<div id="body">标签里。比如:
<div id="body"> <form method="POST" action="{{ route('login') }}"> <!-- 表单内容、错误提示等 --> </form> </div>
要是没有这个容器,加上就行,这样PJAX中间件就能正确提取响应内容了。
解决方案二:让认证POST请求跳过PJAX处理
其实登录、注册这类表单提交请求本来就不适合用PJAX处理,尤其是带验证逻辑的场景。我们可以直接让这些请求绕过PJAX中间件:
修改app/Http/Middleware/FilterIfPjax.php的handle方法,在最前面加一段判断:
public function handle($request, Closure $next) { // 跳过登录和注册的POST请求 $authPaths = ['login', 'register']; if ($request->isMethod('POST') && in_array($request->path(), $authPaths)) { return $next($request); } // 下面是原来的PJAX处理代码 if (! $request->pjax()) { return $next($request); } $response = $next($request); // ... 原有的中间件逻辑 }
这样登录表单提交就会走正常的Laravel流程,不会被PJAX拦截处理,自然就不会出现422错误了。
解决方案三:前端配置排除表单提交
如果你用的是jQuery PJAX这类前端库,也可以在初始化的时候指定只拦截GET请求,或者直接排除表单的提交事件:
// 只对GET请求的链接启用PJAX $(document).pjax('a:not([data-no-pjax])', '#body', { method: 'GET' }); // 或者直接禁用表单的PJAX处理 $('form').on('submit', function() { $.pjax.disable(); });
这样表单提交的时候就不会触发PJAX,也就不会触发中间件的容器提取逻辑了。
额外提示:如果非要用PJAX处理登录POST请求
如果你确实需要PJAX处理登录提交,那得在验证失败时确保返回的视图包含#body容器,并且在控制器里手动处理PJAX响应。比如在LoginController里修改登录方法:
use Illuminate\Support\Facades\Validator; protected function login(Request $request) { $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'password' => 'required', ]); if ($validator->fails()) { if ($request->pjax()) { // 返回带错误信息的登录视图,确保有#body容器 return response()->view('auth.login', [ 'errors' => $validator->errors(), 'email' => $request->email ]); } return redirect()->back()->withErrors($validator)->withInput(); } // 原有的登录逻辑... }
这样验证失败时返回的响应能被PJAX正确解析,不会触发422错误。
内容的提问来源于stack exchange,提问作者Ariel Pepito

