Laravel 如何优雅地实现输出结构统一的功能?

更新日期: 2019-08-02阅读: 2.5k标签: Laravel

背景

一般的项目需求都会要求统一的输出结构,特别是对于api应用而言。因此,如果有beforeResponse的功能,则可以在数据输出之前对response进行统一格式化处理。

假设这么一种场景,应用做api开发,使用抛异常的方式(自定义异常类ApiException)返回无效非法请求的情况。正常请求则返回合法数据(数组或可序列化的模型),希望返回的数据格式

正常请求返回数据格式:

{
  "code":0,
  "data":[

  ],
  "message":""
}

异常请求返回数据格式:

{
  "code":400,
  "data":[

  ],
  "message":"错误提示"
}


Laravel 的设计如何实现

Laravel中的中间件确实支持beforeResponse操作,支持在中间件中进行格式化。但是,这里仅限于正常返回。那么如果控制器抛了异常又改怎么办呢?

Laravel的调用链使得控制器里的异常在正常情况下,还没有抛到中间件就被系统注册的ExceptionHandler类拦截处理了。github上也有关于中间件不能捕获控制器异常的问题Can't catch exception in middleware

作者给出的结论是,Laravel本身的设计就是将异常处理放在ExceptionHandler中。

Yes, this is the beavhiour starting from L5.2. Throwing an exception causes the response to be set as that returned from the exception handler, and then the middleware is allowed to backout from that point.
We don't recommend you write try catch blocks in middleware. Instead, handle exceptions inside the exception handler. Perhaps https://github.com/GrahamCampbell/Laravel-Exceptions would be of use to you?

那么,按照Laravel的设计,正常的请求,我们在一个中间件 FormaterResponse 处理,处理逻辑如下:

<?php
namespace App\Http\Middleware;
use App\Http\Middleware\Closure;
use \Exception;
class FormaterResponse
{
  public function handle($request, \Closure $next)
  {
    $response = $next($request);
    $content = $response->getData();
    $content = [
      'code'=>0,
      'message'=>'',
      'data'=>$content
    ];
    $response->setData($content);
    return $response;
  }
}


错误返回,我们在 app\Exceptions\Handler 中 render 方法处理,格式化,处理逻辑如下:

public function render($request, Exception $e)
{
  if($e instanceof ApiException)
  {
    $response = [
      'code'=>$e->getCode(),
      'message'=>$e->getMessage(),
      'data'=>[]
    ];
    return response()->json($response, 200);
  }
  parent::render($request,$e);
}


更好的方式

上面的这种做法有一个弊端,如果某些模块下想要的数据格式返回不一样,对应异常情况的处理会比较麻烦。因为ExceptionHandler是对一个全局的处理。如果能把数据格式化都放在中间件处理,则可以非常灵活。

其实需要改动的内容非常上,只需要在ExceptionHandler中的handle方法中,对于自定义异常类 ApiException 继续向上抛出去就可以在 middleware 捕获到异常,进而对异常放回进行格式化。

修改之后 App\Exceptions\Handler 中render的代码如下:

public function render($request, Exception $e)
{
  if($e instanceof ApiException)
  {
    throw $e;
  }
  parent::render($request,$e);
}
<?php

namespace App\Http\Middleware;
use App\Http\Middleware\Closure;
use App\Exceptions\ApiException;
class FormaterResponse
{
  public function handle($request, \Closure $next)
  {
    $code = 0;
    $msg = '';
    $data = [];
    try{
      $response = $next($request);
      $data = $response->getData();
    }catch(ApiException $e){
      $code = $e->getCode();
      $msg = $e->getMessage();
      $response = response()->json([],200);
    }
    $content = [
      'code'=>$code,
      'message'=>$msg,
      'data'=>$data
    ];
    $response->setData($content);
    return $response;
  }
}

这样就可以在所有应用 FormaterResponse 的路由中实现beforeRespons 功能,格式化统一的数据输出。

来自:https://mp.weixin.qq.com/s/zZT1Oc0PoqEEW8V5IOdgRg


链接: https://fly63.com/article/detial/4473

分享 10 个你可能不知道的 Laravel Eloquent 小技巧

Laravel 是一个功能丰富的框架。但是,你无法从官方文档中找到所有可用的功能。以下是一些你可能不知道的功能。获取原始属性:当修改一条 Eloquent 模型记录的时候你可以通过调用

laravel常用路径保存

laravel框架常用目录路径:app_path(),app_path函数返回app目录的绝对路径:$path = app_path();你还可以使用app_path函数为相对于app目录的给定文件生成绝对路径:$path = app_path(\\\'Http/Controllers/Controller.php\\\');

Laravel 框架 Model 对象转 json 字符串丢失更新

Laravel 的 Illuminate\\\\Database\\\\Eloquent\\\\Model 实现了 JsonSerializable 接口,所以在调用 json_encode 进行序列化时,会调用 Model::jsonSerialize 方法,他这个方法返回的数据是:

Laravel 中创建 Zip 压缩文件并提供下载

如果您需要您的用户支持多文件下载的话,最好的办法是创建一个压缩包并提供下载。看下在 Laravel 中的实现。事实上,这不是关于 Laravel 的,而是和 PHP 的关联更

Laravel中9个不经常用的小技巧

更新父表的timestamps:如果你想在更新关联表的同时,更新父表的timestamps,你只需要在关联表的model中添加touches属性。

Laravel中集成PayPal

最近在写一个面向国外买家的一个商城项目,既然面向国外,那就要用到PayPal这个支付平台。因为在对接PayPal的过程中遇到了一些问题,花费了一些时间,所以把对接的过程记下来,也希望能帮助到用到PayPal的朋友。我集成的是paypal/rest-api-sdk-php。

十五个常用的 Laravel 集合(Collection)

Laravel Eloquent 通常返回一个集合作为结果,集合包含很多有用的、功能强大的方法。你可以很方便的对集合进行过滤、修改等操作。本次教程就一起来看一看集合的常用方法及功能。

十个推荐使用的 Laravel 的辅助函数

Laravel 包含各种全局辅助函数。 laravel 中包含大量辅助函数,您可以使用它们来简化开发工作流程。 在这里,我将编写10个最好的 laravel 帮助函数,用于使我的开发更容易。 您必须考虑在必要时使用它们。

Laravel 向公共模板赋值

开发过程中许多时候都会向公共模板赋值,比如顶部导航栏,页面底部等等,不可能在每个控制器中都赋值一遍。Laravel 中解决办法如下:

Composer,laravel下载和更新

有两种方式启用本镜像服务:系统全局配置: 即将配置信息添加到 Composer 的全局配置文件 config.json 中。单个项目配置: 将配置信息添加到某个项目的composer.json 文件中。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!