Laravel 10接口测试验证错误时为何返回302而非400?
问题:Laravel 10中表单验证失败返回302而非400 Bad Request
我在Laravel 10项目中编写了如下测试方法:
public function testAdded() { // Test Data Setup $tagModel = Tag::factory()->make([]); // model only in memory // Test Action // $tagModel->name = ''; $response = $this ->post(route('tags.store'), $tagModel->toArray()); $response ->assertStatus(201); // READ TAG CREATED ABOVE $insertedTag = Tag::getBySearch(search: $tagModel->name, partial: false) ->first(); $this->assertNotNull($insertedTag, 'Inserted tag not found'); $this->assertEquals( $insertedTag->name, $tagModel->name, 'Name read is not equal name on insert' ); }
原本测试运行正常,取消注释$tagModel->name = '';后,测试报错:
├ Expected response status code [201] but received 302. ├ Failed asserting that 201 is identical to 302. ├ ├ The following errors occurred during the last request: ├ ├ The name field is required. │
明明看到验证错误提示,但返回的HTTP状态码是302(临时重定向),而非预期的400 Bad Request。
路由tags.store对应的控制器方法使用自定义的CreateTagRequest类验证,规则如下:
[ 'name' => [ 'required', 'string', 'max:100', ], ]
控制器方法逻辑:
public function store(CreateTagRequest $request) { try { $tag = $this->tagCrudRepository->store(data: $request->only('name')); return response()->json(['tag' => (new TagResource($tag))], 201); } catch (\Error | \Exception $e) { \Log::info($e->getMessage()); return response()->json([ 'error_message' => $e->getMessage(), ], 500); } }
原因与解决方法
核心原因:Laravel默认验证响应逻辑
Laravel表单请求验证对非AJAX请求默认返回302重定向,将验证错误存入session并跳转回原页面。你的测试请求没有携带AJAX标识头,Laravel判定为普通表单提交,因此返回302。测试的问题:未模拟AJAX请求
你的控制器返回JSON响应,说明这是AJAX接口,但测试中没有设置AJAX请求头,导致Laravel触发了普通表单的验证失败逻辑。解决步骤
- 修改测试请求,添加AJAX标识:
$response = $this ->ajax() // 等价于设置X-Requested-With: XMLHttpRequest头 ->post(route('tags.store'), $tagModel->toArray()); - 针对验证失败的场景,调整断言逻辑:
$response->assertStatus(400) ->assertJsonValidationErrors('name');
- 修改测试请求,添加AJAX标识:
内容的提问来源于stack exchange,提问作者mstdmstd
相关产品推荐
相关产品推荐

