laravel 即使提供了自定义消息,验证失败也会返回默认错误消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46257191/
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:39:48  来源:igfitidea点击:

Failed validation returns default error message even though custom messages supplied

laravellaravel-5laravel-validationlaravel-5.5

提问by quinny

I'm not getting the response I expect.

我没有得到我期望的回应。

This is the controller code for a Location web-service request:

这是位置网络服务请求的控制器代码:

<?php
namespace App\Http\Controllers;

use App\Location;
use Illuminate\Http\Request;


class LocationController extends Controller
{


    /**
     * Action method to add a location with the supplied Data
     * 
     * @param \Illuminate\Http\Request $p_oRequest Request
     * 
     * @return JSON
     */
    public function add(Request $p_oRequest)
    {

        try {

            $p_oRequest->validate(
                array(
                    'name' => 'required|alpha_num',
                    'user_id' => 'required|integer',
                ),
                array(
                    'name.required' => 'Name is required',
                    'name.string' => 'Name must be alphanumeric',
                    'user_id.required' => 'Curator User Id is required',
                    'user_id.required' => 'Curator User Id must be an integer',
                )
            );

        } catch (\Exception $ex) {

            $arrResponse = array(
                'result' => 0,
                'reason' => $ex->getMessage(),
                'data' => array(),
                'statusCode' => 404
            );

        } finally {

            return response()->json($arrResponse);

        }

    }

}

The request is http://mydomain/index.php/api/v1/location/add?name=@!^

请求是http://mydomain/index.php/api/v1/location/add?name=@!^

The response reason I expect is: { "result": 0, "reason": "Name must be alphanumeric", "data": [], "statusCode": 404 }

我期望的响应原因是:{ "result": 0, "reason": "Name must be alphanumeric", "data": [], "statusCode": 404 }

The actual response I get instead is: { "result": 0, "reason": "The given data was invalid.", "data": [], "statusCode": 404 }

我得到的实际响应是:{ "result": 0, "reason": "The given data was invalid.", "data": [], "statusCode": 404 }

Please help. This is bugging me.

请帮忙。这是困扰我。

回答by quinny

I've finally discovered why this isn't working. It's not an issue of errors in the implementing code or Laravel, but one of either: (i). writing good PHP code to handle the self-evident result, which clearly I didn't do; (ii). insufficient documentation within Laravel on how to actually use the validation error response. Take your pick.

我终于发现了为什么这不起作用。这不是实现代码或 Laravel 中的错误问题,而是其中之一:(i)。编写好的 PHP 代码来处理不言而喻的结果,这显然是我没有做的;(二)。Laravel 中关于如何实际使用验证错误响应的文档不足。随你挑。

Laravel's validation throws a Illuminate\Validation\ValidationError. Believe it or not, this actually defaults the error message to "The given data was invalid.", so when you catch an \Exception and retrieve its $e->getMessage(), this default error-message is what you (correctly) get.

Laravel 的验证会抛出一个 Illuminate\Validation\ValidationError。信不信由你,这实际上将错误消息默认为“给定的数据无效。”,因此当您捕获 \Exception 并检索其 $e->getMessage() 时,此默认错误消息就是您(正确地)得到。

What you need to do is capture the \Illuminate\Validation\ValidationError - which I should've done originally, duh! - and then use its methods to help you distill the error messages from it.

您需要做的是捕获 \Illuminate\Validation\ValidationError - 我本来应该这样做的,呵呵!- 然后使用它的方法来帮助您从中提取错误消息。

Here's the solution I've come up with:

这是我想出的解决方案:

<?php
namespace App\Http\Controllers;

use App\Location;
use Illuminate\Http\Request;


class LocationController extends Controller
{

    /**
     * Action method to add a location with the supplied Data
     * 
     * @param \Illuminate\Http\Request $p_oRequest Request
     * 
     * @return JSON
     */
    public function add(Request $p_oRequest)
    {
        try {

            $arrValid = array(
                'name' => 'required|alpha_num',
                'user_id' => 'required|integer',
            );
            $p_oRequest->validate(
                $arrValid,
                array(
                    'name.required' => 'Name is missing',
                    'name.alpha_num' => 'Name must be alphanumeric',
                    'user_id.required' => 'User Id is missing',
                    'user_id.integer' => 'User Id must be an integer',
                )
            );

        } catch (\Illuminate\Validate\ValidationException $e ) {

            /**
             * Validation failed
             * Tell the end-user why
             */
            $arrError = $e->errors(); // Useful method - thank you Laravel
            /**
             * Compile a string of error-messages
             */
            foreach ($arrValid as $key=>$value ) {
                $arrImplode[] = implode( ', ', $arrError[$key] );
            }
            $message = implode(', ', $arrImplode);
            /**
             * Populate the respose array for the JSON
             */
            $arrResponse = array(
                'result' => 0,
                'reason' => $message,
                'data' => array(),
                'statusCode' => $e->status,
            );

        } catch (\Exception $ex) {

            $arrResponse = array(
                'result' => 0,
                'reason' => $ex->getMessage(),
                'data' => array(),
                'statusCode' => 404
            );

        } finally {

            return response()->json($arrResponse);

        }

    }

}

So, indeed, Laravel was supplying the correct response, and did what it said on the side of the tin, but I wasn't applying it correctly. Regardless, as a help to future me and other lost PHP-mariners at Laravel-sea, I provide the solution.

所以,确实,Laravel 提供了正确的响应,并按照它在罐头一侧所说的做了,但我没有正确应用它。无论如何,为了帮助我和其他在 Laravel-sea 迷路的 PHP 水手,我提供了解决方案。

In addition, thanks to Marcin for pointing out my buggy coding, which would've caused a problem even if I had implemented the above solution.

此外,感谢 Marcin 指出我的错误编码,即使我实施了上述解决方案,这也会导致问题。

回答by Wilbo Baggins

The problem is probably that Laravel's default Exception handler is not prepared to relay detailed validation info back to the user. Instead, it hides Exception details from the user, which is normally the right thing to do because it might form a security risk for other Exceptions than validation ones.

问题可能是 Laravel 的默认异常处理程序没有准备好将详细的验证信息传递回用户。相反,它对用户隐藏异常详细信息,这通常是正确的做法,因为它可能对验证异常以外的其他异常构成安全风险。

In other words; if the Exception Handler's renderfunction (implemented in /app/Exceptions/Handler.php) catches your validation errors, they will be interpreted as a general application Exception and the general error message relaid to the user will always read 'The given data was invalid'.

换句话说; 如果异常处理程序的render函数(在 中实现/app/Exceptions/Handler.php)捕获您的验证错误,它们将被解释为一般应用程序异常,并且传递给用户的一般错误消息将始终显示为“给定数据无效”。

Make sure the rendermethod ignores instances of \Illuminate\Validation\ValidationException, and you should get the response you expect:

确保该render方法忽略 的实例\Illuminate\Validation\ValidationException,并且您应该得到您期望的响应:

public function render($request, Exception $exception) {

    if (! $exception instanceof \Illuminate\Validation\ValidationException)) {

        // ... render code for other Exceptions here

    }

}

Another way to make the Exception Handler relay ValidationException details with the response would be to do something like this in the rendermethod:

使异常处理程序通过响应中继 ValidationException 详细信息的另一种方法是在render方法中执行以下操作:

if ($exception instanceof ValidationException && $request->expectsJson()) {
    return response()->json(['message' => 'The given data was invalid.', 'errors' => $exception->validator->getMessageBag()], 422);
}

Background

背景

Laravel is basically (ab)using Exceptions here. Normally an Exception indicates a (runtime) problem in the code, but Laravel uses them as a mechanism to facilitate request validation and supply feedback to the user. That's why, in this case, it would be incorrect to let your Exception Handler handle the Exception -- it's not an application Exception, it's info meant for the user.

Laravel 基本上 (ab) 在这里使用异常。通常 Exception 表示代码中的(运行时)问题,但 Laravel 使用它们作为一种机制来促进请求验证并向用户提供反馈。这就是为什么在这种情况下,让您的异常处理程序处理异常是不正确的——它不是应用程序异常,它是为用户提供的信息。

The code in the answer supplied by OP works, because he catches the ValidationException himself, preventing it to be caught by the application's Exception Handler. There is no scenario in which I think that would be wanted as it's a clear mix of concerns and makes for horribly long and unreadable code. Simply ignoring ValidationExceptions or treating them differently in the Exception Handler like I showed above should do the trick just fine.

OP 提供的答案中的代码有效,因为他自己捕获了 ValidationException,防止它被应用程序的异常处理程序捕获。我认为没有任何一种情况是需要的,因为它是一个明显的混合问题,并且会产生非常长且不可读的代码。简单地忽略 ValidationExceptions 或像我上面展示的那样在 Exception Handler 中以不同的方式对待它们应该可以很好地解决问题。

回答by justrusty

I've only just seen this but all you need to do is move the validate call beforethe try/catch

我刚刚看到这个,但你需要做的就是在 try/catch之前移动验证调用

$p_oRequest->validate(
    [
        'name'    => 'required|alpha_num',
        'user_id' => 'required|integer',
    ],
    [
        'name.required'    => 'Name is required',
        'name.string'      => 'Name must be alphanumeric',
        'user_id.required' => 'Curator User Id is required',
        'user_id.required' => 'Curator User Id must be an integer',
    ]
);

try {

...

} catch(\Exception $e) {
    return back()->withErrors($e->getMessage())->withInput();
}

Because Laravel catches the validation exception automatically and returns you back with old input and an array of errors which you can output like

因为 Laravel 会自动捕获验证异常并返回旧输入和一系列错误,您可以像这样输出

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

回答by Marcin Nabia?ek

Your messages should be validation rules, so instead of:

您的消息应该是验证规则,而不是:

'name.required' => 'Name is required',
'name.string' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.required' => 'Curator User Id must be an integer',

you should have:

你应该有:

'name.required' => 'Name is required',
'name.alpha_num' => 'Name must be alphanumeric',
'user_id.required' => 'Curator User Id is required',
'user_id.integer' => 'Curator User Id must be an integer',