Отключить перенаправление проверки запроса в Laravel 5.4

Итак, я пытаюсь разработать API отдыха для внутреннего проекта, и у меня возникает проблема, когда при сбое проверки запроса формы отображается ответ @index.

Итак, у меня есть два пути;

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

@index перечисляет всех клиентов, @store создает нового клиента, и у меня есть валидатор запроса формы для @store метода, который проверяет, предоставлено ли имя для клиента.

Я хочу, чтобы в случае сбоя валидатора отображался ответ JSON с ошибками валидации. Но я думаю, что это происходит, так это сбой проверки, поэтому он перенаправляется обратно на ту же страницу, но перенаправляется GET вместо POST, поэтому вместо этого он перечисляет всех клиентов.

Я знаю, что вы можете настроить свои заголовки так, чтобы они выглядели как запрос ajax, в котором он будет правильно отображать ответ JSON, но я хочу, чтобы он отображал ответ JSON независимо от того, является ли он ajax или нет.

Я попытался переопределить метод response в моем валидаторе, который не работал, я попытался установить метод wantsJson в валидаторе так, чтобы он возвращал истину, что снова не сработало.

Помощь будет очень признательна.

Код ниже ...

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

person KeironLowe    schedule 21.09.2017    source источник


Ответы (7)


Вы можете попробовать вот так

Включите использование сначала, как показано ниже, в свой запрос формы

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

а потом

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

теперь, если вы попытаетесь проверить, он вернется как

{
"title": [
"The  title field is required."
]
}
person Vision Coderz    schedule 21.09.2017
comment
именно то, что я ищу! - person ichimaru; 21.07.2020
comment
Так приятно видеть в Интернете хорошо продуманный вопрос о Laravel и соответствующий ответ! - person Max; 27.09.2020

При запросе мы должны отправить информацию заголовка.

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

Вот и все, теперь laravel не будет перенаправлять и отправлять сообщение об ошибке как JSON.

person Christophvh    schedule 05.10.2018
comment
да, вот с чем я сейчас сталкиваюсь, когда использую почтальон. Если проверка завершилась неудачно, сообщение об ошибке отсутствует. он просто перенаправляет на страницу индекса. Спасибо чувак... - person hendra1; 13.12.2018
comment
Вы можете настроить в сценариях предварительного запроса вашей коллекции автоматическую установку заголовка Accept: pm.request.headers.upsert({ key: 'Accept', value: 'application/json' }) - person Anderson Madeira; 17.05.2020

Попробуй это

Откройте файл 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

person Dmitry Guzun    schedule 19.02.2018

Есть два способа работать с ошибками валидатора, я предлагаю второй способ:

1. Во-первых, просто вернуть ошибку при сбое проверки (в контроллере). Пример:

    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);
person Amin Shojaei    schedule 19.06.2019

Просто используйте эту особенность, чтобы предотвратить перенаправление после FormRequest проверки. Следующая черта также приносит некоторые полезные общедоступные методы, такие как:

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

Надеюсь, вы найдете это полезным.

person Fatalist    schedule 17.12.2019

Я только что создал 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
{
    // ...
person RousseauAlexandre    schedule 31.01.2019

Я сделал промежуточное ПО (только для запросов 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);
    }
}

Таким образом, я всегда получаю ответ JSON с ошибкой проверки, а не перенаправление на страницу веб-индекса.

person Attila Szeremi    schedule 03.09.2019