中间件 +request validator 组合验证接口数据,怎么实现?

在写接口的时候,基础字段其实是固定的,这个时候,如果还要在每个接口的数据验证中,去重复的写基础字段的验证,真的是很累很麻烦
然后就想,能不能在中间件中,统一来验证呢?
请求数据:

{
    "appid": "m60",
    "nonce_str": "51ad4b447724b4cb0c9cdd225911b016",
    "sign": "7299466b424c755121a5d311385ad1ba",
    "body": "[{\"goods_name\": \"1602\",\"goods\": \"1602_T3171205831\",\"data\":[{\"gbCode\":\"6922045339140\",\"actQty\":\"3\"},{\"gbCode\":\"6922045339225\",\"actQty\":\"5\"}]}]",
    "timestamp": "1525845577",
    "sign_type": "MD5"
}

方案一:

// 验证规则:
namespace App\Http\Requests\Api;
use App\Logic\ApiRequest;
class BaseRequest extends ApiRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'appid'     => 'required',
            'timestamp' => 'required',
            'nonce_str' => 'required',
            'sign'      => 'required',
            'body'      => 'required',
        ];
    }
}
// 中间件中的handle代码:
    public function handle(BaseRequest $request, Closure $next)
    {
                return $next($request);
    }

但是这种用法是失败的,直接报错:

Type error: Argument 1 passed to App\Http\Middleware\ApiCheck::handle() must be an instance of App\Http\Requests\Api\BaseRequest, instance of Illuminate\Http\Request given, called in /Users/username/Valet/pinkr/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php on line 149

于是,就换了另一种方式,方案二:

// 中间件中的代码,也只需要这点儿代码:
    public function handle($request, Closure $next)
    {
        $msg = config('apiFormMsg');

        $rules    = [
            'appid'     => 'required',
            'timestamp' => 'required',
            'nonce_str' => 'required',
            'sign'      => 'required',
            'body'      => 'required',
        ];
        $messages = [
            'appid.required'     => $msg['required']['appid'],
            'timestamp.required' => $msg['required']['timestamp'],
            'nonce_str.required' => $msg['required']['nonce_str'],
            'sign.required'      => $msg['required']['sign'],
            'body.required'      => $msg['required']['body'],
        ];

        $validator = Validator::make(json_decode($request->getContent(), true), $rules, $messages);
        if ($validator->fails()) {
            return $this->dataFormat(407, $validator->messages());
        }

        return $next($request);
    }

希望有更好的实现方式,可以替换掉方案二的代码,求分享,谢谢!

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

@Nixus 说到根据method判断,我突然有一个想法,就是你就写一个总的request,然后根据路由来组织验证不就可以了吗?

// 验证规则:
namespace App\Http\Requests\Api;
use App\Logic\ApiRequest;
class BaseRequest extends ApiRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        // 肯定会验证的一些字段
        $rules = [
            'most_validate' => 'required'
        ];
        // 这里你可以根据路由名称或者干脆直接action来判断
        switch ($this->route()->getName()) {
            case 'create_book':
                $rules['book_name'] = 'required';
                break;
            case 'create_user':
                $rules['username'] = 'required';
                break;
        }

        return $rules;
    }
}

这样应该可以复用一些验证吧。
至于你说的错误信息,我也没有什么其他的办法,也是这样写的。

5年前 评论
讨论数量: 8

我不太明白你的意思,你把BaseRequest放到controller的方法参数列表去不就行了吗?比如:

XxxxController::someMethod(BaseRequest $request)
5年前 评论

没事,我其实就是想少写点儿代码;
如果每个方法中都使用BaseRequest,那别的数据怎么验证?只能在方法中再写代码去验证数据了,麻烦,还不如上面的方案二呢

5年前 评论

我在项目中,每个post和put请求都会有自己的request类,最多相同资源的两种请求在request类中通过判断method来改变验证规则.

5年前 评论

@zedisdog 噢,我也是不停的make:request,但是有重复的字段又不能复用,真的是不能忍!
你的错误消息是怎么写的?直接这样吗?

public function messages(){
    return [
        'id.required'=>'错误信息...',
    ];
}

还是有别的什么更好的方式?

5年前 评论

@Nixus 说到根据method判断,我突然有一个想法,就是你就写一个总的request,然后根据路由来组织验证不就可以了吗?

// 验证规则:
namespace App\Http\Requests\Api;
use App\Logic\ApiRequest;
class BaseRequest extends ApiRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        // 肯定会验证的一些字段
        $rules = [
            'most_validate' => 'required'
        ];
        // 这里你可以根据路由名称或者干脆直接action来判断
        switch ($this->route()->getName()) {
            case 'create_book':
                $rules['book_name'] = 'required';
                break;
            case 'create_user':
                $rules['username'] = 'required';
                break;
        }

        return $rules;
    }
}

这样应该可以复用一些验证吧。
至于你说的错误信息,我也没有什么其他的办法,也是这样写的。

5年前 评论

@zedisdog 666,太棒了!
错误信息那个,我弄了一个config文件,也就是在config目录中,新建了一个errors.php,然后:

<?php
return [
    'required'=>[
        'id'=>'错误信息',
    ]
];

// 调用:
<?php
public function messages(){
    $msg = config('errors');
    return [
        'id.required'=> $msg['required']['id'],
    ];
}

如果单个使用错误信息的话,config('errors.required.id');这样就可以了
如果遇到更好的方式,希望可以回来分享,谢谢!

5年前 评论

@Nixus 这种方式的话,其实你可以直接用trans了,跟你的这个原理差不多,而且还带了翻译功能:smile:

5年前 评论

@zedisdog 是的,trans这种更适合,在选用config的时候,完全没有意识到这点儿,现在也只能先这样用了,以后迭代的时候,再改吧!谢谢!

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!