dingo 内部调用时使用 Laravel 的表单验证问题

  1. dingo 中内部接口调用, 当使用 laravel (版本 5.5) 表单验证时, 接口会一直报出 422 状态码错误。

  2. 相关代码如下:

    • 业务逻辑:提交体验课时创建一个学员
    • 相关控制器代码如下:

      • 提交体验课

        $request->validate([
            'phone' => ['required', 'regex:/^1[3456789]\d{9}$/'],
            'name' => ['required'],
        ]);
        
        // 调用创建学员接口
        $this->api->with($request->all())->post('/api/students');
      • 创建学员

        $request->validate([
            'phone' => ['required', Rule::unique('students', 'phone')],
            'datasoure' => ['required'],
        ]);
  3. 接口返回:

    "message": "422 Unprocessable Entity",
    "status_code": 422,
  4. 体验课提交 接口验证可以通过, 创建学员 接口验证通不过; 依赖注入时的是 Illuminate\Http\Request 对象; 但是发现 dingo 内部调用时实例化后的是 InternalRequest 对象; 但是实则是继承关系; 希望得到解决方法. 谢谢

sane丶:bowtie:
sane
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 3
JeffreyBool

/app/Http/Controllers/Api/Controller.php

<?php
/**
 * Created by PhpStorm.
 * User: JeffreyBool
 * Date: 2018/8/26
 * Time: 22:42
 */
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use Dingo\Api\Routing\Helpers;
use App\Http\Controllers\Controller as BaseController;
class Controller extends BaseController{
    use Helpers;
    protected $reservedWords = ['page', 'per_page', 'filters'];
    protected function ignoreReserved(array $params)
    {
        foreach ( $this->reservedWords as $reservedKey ) {
            if (array_key_exists($reservedKey, $params)) {
                unset($params[$reservedKey]);
            }
        }
        return $params;
    }
    protected function validateRequest(Request $request,string $name = null)
    {
        if(!$validator = $this->getValidator($request, $name)) {
            return;
        }
        $rules = array_get($validator, 'rules', []);
        $messages = array_get($validator, 'messages', []);
        $this->validate($request, $rules, $messages);
    }
    private function getValidator(Request $request,string $name = null)
    {
        list($controller, $method) = explode('@', $request->route()->action['uses']);
        $method = $name ?: $method;
        $class = str_replace('Controller', 'Validation', $controller);
        if(!class_exists($class) || !method_exists($class, $method)) {
            return false;
        }
        return call_user_func([new $class, $method]);
    }
}

上面是公共的控制器,写的控制器继承这个控制器即可

使用

app/Http/Validations/Api/Front/ArticlesValidation.php

<?php
namespace App\Http\Validations\Api\Front;
class ArticlesValidation
{
    public function store()
    {
        return [
            'rules' => [
                'title'       => 'required|min:2',
                'body'        => 'required|min:3',
                'category_id' => 'required|numeric',
            ],
            'messages' => [
                'title.required'       => '标题不能为空',
                'title.min'            => '标题必须至少两个字符',
                'category_id.required' => '分类不能为空',
                'body.required'        => '文章内容不能为空',
                'body.min'             => '文章内容必须至少三个字符',
            ],
        ];
    }
}

app/Http/Controllers/Api/Front/ArticlesController.php

<?php
/**
 * Created by PhpStorm.
 * User: JeffreyBool
 * Date: 2019/3/25
 * Time: 00:29
 */
namespace App\Http\Controllers\Api\Front;
use App\Models\User;
use App\Models\Article;
use Illuminate\Http\Request;
use App\Transformers\ArticleTransformer;
use App\Http\Controllers\Api\Controller;
use App\Http\Controllers\Api\Traits\Markdown;
use App\Transformers\ArticleDetailTransformer;
class ArticlesController extends Controller
{
    use Markdown;
    public function __construct()
    {
        $this->middleware('api', ['except' => ['index','show','markdown','hot','userArticles']]);
    }

    /**
     * 添加文章
     * @param Request $request
     * @param Article $article
     * @return \Dingo\Api\Http\Response
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function store(Request $request, Article $article)
    {
        $this->authorize('store', $this->user());  
        $this->validateRequest($request); //这里调用自定义的验证器
        $article->fill($request->all());
        $article->body = $this->convertMarkdownToHtml($request->get('body'));
        $article->excerpt = make_excerpt($article->body);
        $article->body_original = $request->get('body');
        $article->user_id = auth()->id();
        $article->save();
        return $this->response->item($article, new ArticleTransformer())->setStatusCode(201);
    }
}

错误处理

需要去app/Providers/AppServiceProvider.php 手动捕获 ValidationException 异常

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\ValidationException;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        \Carbon\Carbon::setLocale('zh');
        \App\Models\User::observe(\App\Observers\UserObserver::class);
        \App\Models\Reply::observe(\App\Observers\ReplyObserver::class);
        \App\Models\Article::observe(\App\Observers\ArticleObserver::class);
    }
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        if ($this->app->environment() !== 'production') {
            $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
        }
        \API::error(function (\Illuminate\Auth\Access\AuthorizationException $exception) {
            abort(403, $exception->getMessage());
        });
        \API::error(function (\Illuminate\Database\Eloquent\ModelNotFoundException $exception) {
            abort(404);
        });
        \API::error(function (ValidationException $exception) {
            $firstMessage = array_first($exception->errors());
            $firstMessage = is_array($firstMessage) ? array_first($firstMessage) : $firstMessage;;
            abort(422,$firstMessage);
        });
    }
}

以上代码应该就是我使用 dingo api处理接口错误的逻辑了

4年前 评论
sane

@kenuo 谢谢 关于这个问题, 实则是本人并没有完全理解 laravel 表单验证逻辑, 因为 创建学员 接口中的 unique 规则不通过, 但没有详细的报错信息, 只有状态码, 所以一直没弄清楚问题出现在哪里, 一直以为是内部调用失败.

解决方案如下:

try {
   $this->api->with($request->all())->post('/api/students');
 } catch (ValidationException $e) {
 }

忽略掉错误的抛出

4年前 评论
JeffreyBool

@sane

 \API::error(function (ValidationException $exception) {
            $firstMessage = array_first($exception->errors());
            $firstMessage = is_array($firstMessage) ? array_first($firstMessage) : $firstMessage;;
            abort(422,$firstMessage);
        });

我这里就是手动捕获 ValidationException 错误。返回返回给前端啊

4年前 评论

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