在 Laravel 5.4 中禁用请求验证重定向
Disable request validation redirect in Laravel 5.4
所以我正在尝试为一个内部项目开发一个休息 API,我遇到了一个问题,当表单请求验证失败时,它显示了@index 响应。
所以我有两条路线;
Route::get('/api/clients', 'ClientController@index');
Route::post('/api/clients', 'ClientController@store');
@index
列出所有客户端,@store
创建一个新客户端,我在 @store
方法上有一个表单请求验证器,它检查为客户端提供的名称。
我想要的是当验证器失败时,它会显示 JSON 响应并出现验证错误。但我认为发生的事情是验证失败,因此它重定向回同一页面,但重定向是 GET
而不是 POST
,因此它列出了所有客户端。
我知道您可以设置 headers 使其看起来像 ajax 请求,其中它将正确显示 JSON 响应,但我希望它显示JSON 响应,无论是否为 ajax。
我试过在我的验证器中覆盖 response
方法但没有用,我试过将验证器中的 wantsJson
方法设置为 return true 再次没用。
非常感谢您的帮助。
代码如下...
web.php
Route::get('/api/clients', 'ClientController@index');
Route::get('/api/clients/{client}', 'ClientController@show');
Route::post('/api/clients', 'ClientController@store');
Route::put('/api/clients/{id}', 'ClientController@update');
Route::delete('/api/clients/{id}', 'ClientController@delete');
ClientController.php
namespace App\Http\Controllers;
use App\Client;
use App\Http\Requests\ClientRequest;
class ClientController extends Controller
{
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(ClientRequest $request)
{
return Client::create([
'title' => request('title'),
'user_id' => auth()->id()
]);
}
ClientRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ClientRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required'
];
}
/**
* Get the failed validation response for the request.
*
* @param array $errors
* @return JsonResponse
*/
public function response(array $errors)
{
dd('exit'); // Doesn't work
}
}
你可以这样试试
在您的表单请求中包括 use first,如下所示
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
然后
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
现在,如果您尝试验证,那么它会return像
{
"title": [
"The title field is required."
]
}
试试这个
打开 app/Exceptions/Handler.php 文件
包括使用
use Illuminate\Validation\ValidationException;
然后添加方法
/**
* Create a response object from the given validation exception.
*
* @param \Illuminate\Validation\ValidationException $e
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function convertValidationExceptionToResponse(ValidationException $e, $request)
{
if ($e->response) {
return $e->response;
}
return response()->json($e->validator->errors()->getMessages(), 422);
}
现在您可以获得标准的 validationFailure 响应,例如 ajax 请求
发出请求时,我们应该发送 header 信息。
Accept: application/json
Content-Type: application/json
就是这样,现在 laravel 不会将错误消息重定向并发送为 JSON。
我刚刚创建了一个 ApiFormRequest
重写 FormRequest::failedValidation
方法,如下所示:
<?php
// app/Http/Requests/ApiFormRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class ApiFormRequest extends FormRequest
{
protected function failedValidation(Validator $validator): void
{
$jsonResponse = response()->json(['errors' => $validator->errors()], 422);
throw new HttpResponseException($jsonResponse);
}
}
那你就这么用
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ClientRequest extends ApiFormRequest
{
// ...
有两种方法处理验证器错误,我的建议是第二种方法:
1. 第一种方式,当验证失败时(在控制器中)简单地 return 一个错误。
示例:
try {
request()->validate([
'input1' => 'required',
'input2' => 'string|min:5',
]);
} catch (\Illuminate\Validation\ValidationException $e){
return response('The given data was invalid.', 400);
}
方便又干净。
2. 第二种方式是向用户显示完整错误(在控制器中),如下所示:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make(request()->all(), [
'id' => 'required|integer',
'description' => 'string'
]);
// return array of errors to client with status code 400
if ($validator->fails())
return response($validator->messages()->toArray(), 400);
我制作了一个中间件(仅适用于 API 请求)使 Accept header 默认包含 application/json:
/**
* Ensures the default Accept header is application/json
*/
class DefaultApiAcceptJson
{
public function handle(Request $request, \Closure $next)
{
$acceptHeader = $request->headers->get('Accept');
if (!Str::contains($acceptHeader, 'application/json')) {
$newAcceptHeader = 'application/json';
if ($acceptHeader) {
$newAcceptHeader .= "/$acceptHeader";
}
$request->headers->set('Accept', $newAcceptHeader);
}
return $next($request);
}
}
这样我总是得到验证错误 JSON 响应,而不是重定向到 Web 索引页面。
简单地使用这个特性来防止在 FormRequest
验证后重定向。
下面的trait也带来了一些有用的public方法,比如:
validatorPasses()
validatorFails()
validatorErrors()
respondWithErrorsJson(int $code = 422)
redirectWithErrors()
- 恢复默认的 Laravel FomrRequest 行为
特质
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\ValidationException;
trait PreventsRedirectWhenFailedTrait
{
/**
* Default self::failedValidation() Laravel behavior flag.
*
* @var bool
*/
private $defaultFailedValidationRestored = false;
/**
* Check for validator success flag.
*
* @return bool
*/
public function validatorPasses(): bool
{
return !$this->validatorFails();
}
/**
* Check for validator fail flag.
*
* @return bool
*/
public function validatorFails(): bool
{
return $this->getValidatorInstance()->fails();
}
/**
* @return MessageBag
*/
public function validatorErrors(): MessageBag
{
return $this->getValidatorInstance()->errors();
}
/**
* Respond with validator errors in JSON format.
*
* @param int $code
*/
public function respondWithErrorsJson(int $code = 422): void
{
if ($this->validatorFails()) {
throw new HttpResponseException(
response()->json(['errors' => $this->getValidatorInstance()->errors()], $code)
);
}
}
/**
* Restore and apply default self::failedValidation() method behavior.
*
* @throws ValidationException
*/
public function redirectWithErrors(): void
{
$this->defaultFailedValidationRestored = true;
$this->failedValidation($this->getValidatorInstance());
}
/**
* Handle a failed validation attempt.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator): void
{
if ($this->defaultFailedValidationRestored) {
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}
}
用法示例:
namespace App\Http\Requests;
use Auth;
use Illuminate\Foundation\Http\FormRequest;
class AuthRequest extends FormRequest
{
use PreventsRedirectWhenFailedTrait;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return Auth::guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'email' => 'required|email|exists:users',
'password' => 'required',
'remember_me' => 'integer',
];
}
}
在你的控制器中:
public function authenticate(AuthRequest $request)
{
if ($request->validatorPasses()) {
$data = $request->validated();
/* your logic */
} else {
$errorBag = $request->validatorErrors();
}
// or
if ($request->validatorFails()) {
// your logic
}
}
希望对您有所帮助。
所以我正在尝试为一个内部项目开发一个休息 API,我遇到了一个问题,当表单请求验证失败时,它显示了@index 响应。
所以我有两条路线;
Route::get('/api/clients', 'ClientController@index');
Route::post('/api/clients', 'ClientController@store');
@index
列出所有客户端,@store
创建一个新客户端,我在 @store
方法上有一个表单请求验证器,它检查为客户端提供的名称。
我想要的是当验证器失败时,它会显示 JSON 响应并出现验证错误。但我认为发生的事情是验证失败,因此它重定向回同一页面,但重定向是 GET
而不是 POST
,因此它列出了所有客户端。
我知道您可以设置 headers 使其看起来像 ajax 请求,其中它将正确显示 JSON 响应,但我希望它显示JSON 响应,无论是否为 ajax。
我试过在我的验证器中覆盖 response
方法但没有用,我试过将验证器中的 wantsJson
方法设置为 return true 再次没用。
非常感谢您的帮助。
代码如下...
web.php
Route::get('/api/clients', 'ClientController@index');
Route::get('/api/clients/{client}', 'ClientController@show');
Route::post('/api/clients', 'ClientController@store');
Route::put('/api/clients/{id}', 'ClientController@update');
Route::delete('/api/clients/{id}', 'ClientController@delete');
ClientController.php
namespace App\Http\Controllers;
use App\Client;
use App\Http\Requests\ClientRequest;
class ClientController extends Controller
{
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(ClientRequest $request)
{
return Client::create([
'title' => request('title'),
'user_id' => auth()->id()
]);
}
ClientRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ClientRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required'
];
}
/**
* Get the failed validation response for the request.
*
* @param array $errors
* @return JsonResponse
*/
public function response(array $errors)
{
dd('exit'); // Doesn't work
}
}
你可以这样试试
在您的表单请求中包括 use first,如下所示
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
然后
protected function failedValidation(Validator $validator) {
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
现在,如果您尝试验证,那么它会return像
{
"title": [
"The title field is required."
]
}
试试这个
打开 app/Exceptions/Handler.php 文件
包括使用
use Illuminate\Validation\ValidationException;
然后添加方法
/**
* Create a response object from the given validation exception.
*
* @param \Illuminate\Validation\ValidationException $e
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function convertValidationExceptionToResponse(ValidationException $e, $request)
{
if ($e->response) {
return $e->response;
}
return response()->json($e->validator->errors()->getMessages(), 422);
}
现在您可以获得标准的 validationFailure 响应,例如 ajax 请求
发出请求时,我们应该发送 header 信息。
Accept: application/json
Content-Type: application/json
就是这样,现在 laravel 不会将错误消息重定向并发送为 JSON。
我刚刚创建了一个 ApiFormRequest
重写 FormRequest::failedValidation
方法,如下所示:
<?php
// app/Http/Requests/ApiFormRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class ApiFormRequest extends FormRequest
{
protected function failedValidation(Validator $validator): void
{
$jsonResponse = response()->json(['errors' => $validator->errors()], 422);
throw new HttpResponseException($jsonResponse);
}
}
那你就这么用
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ClientRequest extends ApiFormRequest
{
// ...
有两种方法处理验证器错误,我的建议是第二种方法:
1. 第一种方式,当验证失败时(在控制器中)简单地 return 一个错误。 示例:
try {
request()->validate([
'input1' => 'required',
'input2' => 'string|min:5',
]);
} catch (\Illuminate\Validation\ValidationException $e){
return response('The given data was invalid.', 400);
}
方便又干净。
2. 第二种方式是向用户显示完整错误(在控制器中),如下所示:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make(request()->all(), [
'id' => 'required|integer',
'description' => 'string'
]);
// return array of errors to client with status code 400
if ($validator->fails())
return response($validator->messages()->toArray(), 400);
我制作了一个中间件(仅适用于 API 请求)使 Accept header 默认包含 application/json:
/**
* Ensures the default Accept header is application/json
*/
class DefaultApiAcceptJson
{
public function handle(Request $request, \Closure $next)
{
$acceptHeader = $request->headers->get('Accept');
if (!Str::contains($acceptHeader, 'application/json')) {
$newAcceptHeader = 'application/json';
if ($acceptHeader) {
$newAcceptHeader .= "/$acceptHeader";
}
$request->headers->set('Accept', $newAcceptHeader);
}
return $next($request);
}
}
这样我总是得到验证错误 JSON 响应,而不是重定向到 Web 索引页面。
简单地使用这个特性来防止在 FormRequest
验证后重定向。
下面的trait也带来了一些有用的public方法,比如:
validatorPasses()
validatorFails()
validatorErrors()
respondWithErrorsJson(int $code = 422)
redirectWithErrors()
- 恢复默认的 Laravel FomrRequest 行为
特质
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\ValidationException;
trait PreventsRedirectWhenFailedTrait
{
/**
* Default self::failedValidation() Laravel behavior flag.
*
* @var bool
*/
private $defaultFailedValidationRestored = false;
/**
* Check for validator success flag.
*
* @return bool
*/
public function validatorPasses(): bool
{
return !$this->validatorFails();
}
/**
* Check for validator fail flag.
*
* @return bool
*/
public function validatorFails(): bool
{
return $this->getValidatorInstance()->fails();
}
/**
* @return MessageBag
*/
public function validatorErrors(): MessageBag
{
return $this->getValidatorInstance()->errors();
}
/**
* Respond with validator errors in JSON format.
*
* @param int $code
*/
public function respondWithErrorsJson(int $code = 422): void
{
if ($this->validatorFails()) {
throw new HttpResponseException(
response()->json(['errors' => $this->getValidatorInstance()->errors()], $code)
);
}
}
/**
* Restore and apply default self::failedValidation() method behavior.
*
* @throws ValidationException
*/
public function redirectWithErrors(): void
{
$this->defaultFailedValidationRestored = true;
$this->failedValidation($this->getValidatorInstance());
}
/**
* Handle a failed validation attempt.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function failedValidation(Validator $validator): void
{
if ($this->defaultFailedValidationRestored) {
throw (new ValidationException($validator))
->errorBag($this->errorBag)
->redirectTo($this->getRedirectUrl());
}
}
}
用法示例:
namespace App\Http\Requests;
use Auth;
use Illuminate\Foundation\Http\FormRequest;
class AuthRequest extends FormRequest
{
use PreventsRedirectWhenFailedTrait;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize(): bool
{
return Auth::guest();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'email' => 'required|email|exists:users',
'password' => 'required',
'remember_me' => 'integer',
];
}
}
在你的控制器中:
public function authenticate(AuthRequest $request)
{
if ($request->validatorPasses()) {
$data = $request->validated();
/* your logic */
} else {
$errorBag = $request->validatorErrors();
}
// or
if ($request->validatorFails()) {
// your logic
}
}
希望对您有所帮助。