从路由返回了无效的 JSON。也许抛出了异常?

Posted

技术标签:

【中文标题】从路由返回了无效的 JSON。也许抛出了异常?【英文标题】:Invalid JSON was returned from the route. Perhaps an exception was thrown? 【发布时间】:2017-03-18 17:46:38 【问题描述】:

我一直在努力将JWT authentication 添加到我的 Lumen API。请记住,我是 Lumen、API 设计和 TDD 的新手。在添加身份验证之前,所有测试都通过了。老实说,除了我运行 phpunit 之外,一切似乎都运行良好。难以理解的是,当我在邮递员中运行相同的测试时,我没有任何问题,但是当我在 phpunit 中转储响应时,我得到NULL。或许一双全新的眼睛能帮到我?

我已将 jwt.auth 中间件添加到我的受限路由中:

routes.php

// all other code omitted

$app->group([
  'prefix'     => $version . '/authors',
  'middleware' => 'jwt.auth',
  'namespace'  => 'App\Http\Controllers',
], function ($app) 

  $app->get('/id:[\d]+', ['as' => 'authors.show', 'uses' => 'AuthorsController@show']);  

);

我的部分控制器如下:

AuthorsController.php

class AuthorsController extends Controller


  // all other code omitted

  public function show($id)
  
    return $this->item(Author::findOrFail($id), new AuthorTransformer());
  


我的模型如下

作者.php

class Author extends Model

/**
 * The attributes that are mass assignable
 *
 * @var array
 */
  protected $fillable = ['name', 'biography', 'gender'];

  public function books()
  
    return $this->hasMany(Book::class);
  

而我的Transformer如下:

AuthorTransformer.php

class AuthorTransformer extends TransformerAbstract


  protected $availableIncludes = [
    'books',
  ];

  public function includeBooks(Author $author)
  
    return $this->collection($author->books, new BookTransformer());
  

  /**
   * Transform an author model
   *
   * @param Author $author
   * @return array
   */
  public function transform(Author $author)
  
    return [
      'id'        => $author->id,
      'name'      => $author->name,
      'gender'    => $author->gender,
      'biography' => $author->biography,
      'created'   => $author->created_at->toIso8601String(),
      'updated'   => $author->created_at->toIso8601String(),
    ];
  

我的测试如下:

TestCase.php

class TestCase extends Laravel\Lumen\Testing\TestCase


// all other code omitted

/**
 * Convenience method for creating a user
 *
 * @return $user
 */
  protected function userFactory()
  

    $user = factory(\App\User::class, 1)->create(['password' => app('hash')->make('supersecret')]);

    return $user;
  

/**
 * Convenience method for getting jwt and authenticating
 *
 * @return $body
 */
  protected function jwtAuthTest($method, $url, $body = [])
  
    $user = $this->userFactory();

    $token = JWTAuth::fromUser($user);
    JWTAuth::setToken($token);
    $headers = array(
      "Accept"        => "application/json",
      "Authorization" => "Bearer " . $token,
    );

    switch ($method) 
      case 'get':
        $this->get($url, $body, $headers);
        break;
      case 'post':
        $this->post($url, $body, $headers);
        break;
      case 'put':
        $this->put($url, $body, $headers);
        break;
      case 'patch':
        $this->patch($url, $body, $headers);
        break;
      case 'delete':
        $this->delete($url, $body, $headers);
        break;
    

    $data = json_decode($this->response->getContent(), true);

    return $data;
  


AuthorsControllerTest.php

class AuthorsControllerTest extends TestCase


  // all other code omitted

/** @test **/
  public function show_should_fail_on_an_invalid_author()
  
    $body = $this->jwtAuthTest('get', '/v1/authors/1234');

    // this works fine...
    $this->seeStatusCode(Response::HTTP_NOT_FOUND);

    // NULL??
    var_dump($body);
  

我的回答应该是:


  "error": 
    "message": "Not Found",
    "status": 404
  

但是我收到了NULL

当我在 Postman 中使用有效令牌测试相同的路线时,我得到了,这是我在测试中所期望的:


  "error": 
    "message": "Not Found",
    "status": 404
  

突然我的路由在 phpunit 测试中返回 null。我似乎无法弄清楚为什么?

我的处理程序如下:

// all other code omitted
class Handler extends ExceptionHandler

  /**
   * A list of the exception types that should not be reported.
   *
   * @var array
   */
  protected $dontReport = [
    AuthorizationException::class,
    HttpException::class,
    ModelNotFoundException::class,
    ValidationException::class,
  ];

  /**
   * Report or log an exception.
   *
   * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
   *
   * @param  \Exception  $e
   * @return void
   */
  public function report(Exception $e)
  
    parent::report($e);
  

  /**
   * Render an exception into an HTTP response.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Exception  $e
   * @return \Illuminate\Http\Response
   */
  public function render($request, Exception $e)
  
    if ($request->wantsJson()) 
      $response = [
        'message' => (string) $e->getMessage(),
        'status'  => 400,
      ];

      if ($e instanceof HttpException) 
        $response['message'] = Response::$statusTexts[$e->getStatusCode()];
        $response['status']  = $e->getStatusCode();
       else if ($e instanceof ModelNotFoundException) 
        $response['message'] = Response::$statusTexts[Response::HTTP_NOT_FOUND];
        $response['status']  = Response::HTTP_NOT_FOUND;
      

      if ($this->isDebugMode()) 
        $response['debug'] = [
          'exception' => get_class($e),
          'trace'     => $e->getTrace(),
        ];
      

      return response()->json(['error' => $response], $response['status']);
    

    return parent::render($request, $e);

  


当我的测试失败时,我得到:

There was 1 failure:

1) Tests\App\Http\Controllers\AuthorsControllerTest::show_should_fail_on_an_invalid_author
Invalid JSON was returned from the route. Perhaps an exception was thrown?

如果您需要其他任何东西,请告诉我,并提前感谢您。

源码:https://github.com/studio174/gscp

【问题讨论】:

【参考方案1】:

问题在于TestCase.php 中存在简单的命名冲突和对 get() 方法的无效使用:

TestCase.php

/**
 * Convenience method for getting jwt and authenticating
 *
 * @return $body
 */
  protected function jwtAuthTest($method, $url, $body = [])
  
    $user = $this->userFactory();

    $token = JWTAuth::fromUser($user);
    JWTAuth::setToken($token);
    $headers = array(
      "Accept"        => "application/json",
      "Authorization" => "Bearer " . $token,
    );

    switch ($method) 
      case 'get':
        // [FIX] removed $body from get request as this was overwriting my headers 
        // and causing my handler to return plain text instead of JSON
        $this->get($url,  $headers);
        break;
      case 'post':
        $this->post($url, $body, $headers);
        break;
      case 'put':
        $this->put($url, $body, $headers);
        break;
      case 'patch':
        $this->patch($url, $body, $headers);
        break;
      case 'delete':
        $this->delete($url, $body, $headers);
        break;
    

    // [FIX] changed $body= json_decode($this->response->getContent(), true);
    $data = json_decode($this->response->getContent(), true);

    return $data;
  

【讨论】:

以上是关于从路由返回了无效的 JSON。也许抛出了异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何在C#中解析/反序列化从rest服务返回的JSON

在 JSON.Net 中处理不存在的 JSON 令牌如何返回默认值而不是抛出异常

抛出异常或返回 null 是不是更适合 Java? [复制]

为啥方法在抛出异常后不需要返回值?

Java中子类重写父类的方法为啥返回值类型要小于等于父类方法的返回值类型?

Discord.NET - 获取命令中抛出了哪种类型的异常