在 Laravel 5.4 中禁用请求验证重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46350307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 16:41:30  来源:igfitidea点击:

Disable request validation redirect in Laravel 5.4

jsonlaravelrequest-validation

提问by KeironLowe

So I'm trying to develop a rest API for an internal project, and I've got an issue where when the form request validation fails, it shows the @index response.

所以我正在尝试为一个内部项目开发一个 rest API,我遇到了一个问题,当表单请求验证失败时,它会显示 @index 响应。

So I have two routes;

所以我有两条路线;

Route::get('/api/clients', 'ClientController@index');
Route::post('/api/clients', 'ClientController@store');

@indexlists all clients, @storecreates a new client and I've got a Form Request Validator on the @storemethod which checks a name is provided for the client.

@index列出所有客户端,@store创建一个新客户端,我在@store检查为客户端提供名称的方法上有一个表单请求验证器。

What I want is when the validator fails, it shows a JSON response with the validation errors. But what I think it happening, is the validation fails, so it redirects back to the same page, but the redirect is GETinstead of POST, so it lists all the clients instead.

我想要的是当验证器失败时,它会显示带有验证错误的 JSON 响应。但是我认为它发生的是验证失败,因此它重定向回同一页面,但重定向GET不是POST,因此它列出了所有客户端。

I know that you can set your headers so that it looks like an ajax request, in which it will show the JSON response properly, but I want it to show the JSON response regardless of whether it's ajax or not.

我知道你可以设置你的标题,使它看起来像一个 ajax 请求,它会正确显示 JSON 响应,但我希望它显示 JSON 响应,无论它是否是 ajax。

I've tried overriding the responsemethod in my validator which didn't work, I've tried setting the wantsJsonmethod in the validator to return true which again didn't work.

我试过response在我的验证器中覆盖不起作用的wantsJson方法,我试过将验证器中的方法设置为返回 true,这又不起作用。

Help would be very much appreciated.

非常感谢您的帮助。

Code is below...

代码如下...

web.php

网页.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

客户端控制器.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

<?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
     }
}

回答by iCoders

You can try like this

你可以这样试试

Include use first as below in your form request

在您的表单请求中首先包括如下使用

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

and then

进而

protected function failedValidation(Validator $validator) {
        throw new HttpResponseException(response()->json($validator->errors(), 422));
    }

now if you try to validate then it will return like

现在,如果您尝试验证,那么它会像

{
"title": [
"The  title field is required."
]
}

回答by Christophvh

When making the request we should send header info.

发出请求时,我们应该发送标头信息。

Accept: application/json
Content-Type: application/json

That's it, now laravel will not redirect and send the error message as JSON.

就是这样,现在 laravel 不会重定向并将错误消息作为 JSON 发送。

回答by Dmitry Guzun

Try this

尝试这个

Open app/Exceptions/Handler.php file

打开 app/Exceptions/Handler.php 文件

Include use

包括使用

use Illuminate\Validation\ValidationException;

and then add method

然后添加方法

    /**
     * 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);
    }

now you can get standard validationFailure response like ajax request

现在您可以获得标准的validationFailure 响应,如ajax 请求

回答by RousseauAlexandre

I just created a ApiFormRequestwho override FormRequest::failedValidationmethod like this:

我刚刚创建了一个像这样的ApiFormRequestwho overrideFormRequest::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);
    }
}

Then you simply use like this

然后你只需像这样使用

<?php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ClientRequest extends ApiFormRequest
{
    // ...

回答by Attila Szeremi

I made a middleware (for API requests only) to make the Accept header include application/json by default:

我制作了一个中间件(仅适用于 API 请求)以使 Accept 标头默认包含 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);
    }
}

This way I always get the validation error JSON response rather than a redirect to the web index page.

这样我总是得到验证错误 JSON 响应,而不是重定向到 Web 索引页面。

回答by Amin Shojaei

There is two waysto work with validator errors, my suggestion is second way:

两种方法可以处理验证器错误,我的建议是第二种方法

1.First way, Simply return an error when validation fail's(in controller). Example:

1.第一种方法,当验证失败时(在控制器中)简单地返回一个错误。例子:

    try {
        request()->validate([
            'input1' => 'required',
            'input2' => 'string|min:5',
        ]);

    } catch (\Illuminate\Validation\ValidationException $e){
        return response('The given data was invalid.', 400);

    }

Handy and clean.

方便又干净。

2.Second way is show full errors to user(in controller), like this:

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);

回答by Fatalist

Simply use this trait to prevent redirect after FormRequestvalidation. The following trait is also brings some useful public methods, such as:

只需使用此特征来防止FormRequest验证后重定向。以下 trait 也带来了一些有用的公共方法,例如:

  • validatorPasses()
  • validatorFails()
  • validatorErrors()
  • respondWithErrorsJson(int $code = 422)
  • redirectWithErrors()- restores the default Laravel FomrRequest behavior
  • validatorPasses()
  • validatorFails()
  • validatorErrors()
  • respondWithErrorsJson(int $code = 422)
  • redirectWithErrors()- 恢复默认的 Laravel FormrRequest 行为

Trait

特征

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());
        }
    }
}

Usage example:

用法示例:

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',
        ];
    }
}

Inside your controller:

在您的控制器内部:

public function authenticate(AuthRequest $request)
    {
        if ($request->validatorPasses()) {
            $data = $request->validated();
            /* your logic */
        } else {
            $errorBag = $request->validatorErrors();
        }

        // or
        if ($request->validatorFails()) {
            // your logic
        }
}

Hope you'll find this helpful.

希望你会发现这有帮助。