hyperf 框架完善之接口统一响应
上节课我们已经成功启动了 hyperf,我们的目的是利用 hyperf 实现一套问答系统的接口开发。
在开发需求之前,为了让我们的框架更加完善,先看几个问题。
- 接口统一响应
- 异常类统一处理
- 国际化支持
- 枚举类
- 公共函数库的引入
今天我们先来看第一个问题。
在接口开发中,固定数据结构的响应内容非常有利于客户端解析,所以我们有必要先定义一套统一响应的数据格式。
例如请求失败时,统一返回
{
"code": 错误码,
"message": "Not Found"
}
请求成功时,统一返回
{
"code": 0,
"data": []
}
程序抛出异常时,统一返回,无论是主动抛出还是系统抛出的异常
{
"code": 错误码,
"message": "xxx"
}
来看下实现步骤:
1、Controller 的父类 AbstractController 增加 success 和 fail 方法如下:
public function success($data = [])
{
return $this->response->json([
'code' => 0,
'data' => $data,
]);
}
public function fail($code, $message = '')
{
return $this->response->json([
'code' => $code,
'message' => $message,
]);
}
2、App\Controller\IndexController 增加 AutoController 注解以及测试方法如下:
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
#[AutoController]
class IndexController extends AbstractController
{
public function info($id)
{
if ($id > 0) {
return $this->success(['info' => 'data info']);
} else {
return $this->fail(500, 'id无效');
}
}
}
#[AutoController] 参考 https://hyperf.wiki/3.0/#/zh-cn/router?id=%e9%80%9a%e8%bf%87%e6%b3%a8%e8%a7%a3%e5%ae%9a%e4%b9%89%e8%b7%af%e7%94%b1
3、容器内重启项目
/data/project/questions # php bin/hyperf.php start
4、宿主机内 curl 直接请求测试,结果如下:
curl http://127.0.0.1:9501/index/info\?id\=1
{"code":0,"data":{"info":"data info"}}%
curl http://127.0.0.1:9501/index/info\?id\=0
{"code":500,"message":"id无效"}%
回过头来看第一步中我们在 AbstractController 内增加的 success 和 fail 方法,都是针对 response::json() 方法进行的封装。但是还不够,如果我们在 非 Controller 的类中(比如后面要讲的异常处理器)也需要调 success 和 fail 方法就比较尴尬了。
下面进行一个简单的优化。
在 app 目录下创建 Components 目录,封装一个独立的 Response 类,专门处理统一响应。
<?php
declare(strict_types=1);
namespace App\Components;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;
class Response
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var ResponseInterface
*/
protected $response;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->response = $container->get(ResponseInterface::class);
}
public function success($data = [])
{
return $this->response->json([
'code' => 0,
'data' => $data,
]);
}
public function fail($code, $message = '')
{
return $this->response->json([
'code' => $code,
'message' => $message,
]);
}
}
容器对象 ContainerInterface 参考 https://hyperf.wiki/3.0/#/zh-cn/di?id=%e8%8e%b7%e5%8f%96%e5%ae%b9%e5%99%a8%e5%af%b9%e8%b1%a1
同时,AbstractController 类中注入的 Response 类修改为 App\Components\Response,如下:
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Components\Response;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Container\ContainerInterface;
abstract class AbstractController
{
#[Inject]
protected ContainerInterface $container;
#[Inject]
protected RequestInterface $request;
#[Inject]
protected Response $response;
}
依赖注入参考 https://hyperf.wiki/3.0/#/zh-cn/di
如此一来,我们在 IndexController::info 方法内的调用也需要更新。
public function info()
{
$id = (int) $this->request->input('id', 0);
if ($id > 0) {
return $this->response->success(['info' => 'data info']);
} else {
return $this->response->fail(500, 'id无效');
}
}
也就是说后面我们无论在哪里,只需要注入 App\Components\Response ,都可以直接调用 Response::success(), Response::fail 即可。
看似没有问题,实则漏洞百出。如果程序中主动 throw 你了一个异常,怎么办?
大家可以先自己思考,我们下节课再继续完善。
这块的话,注入容器类有什么作用吗,没看到使用的地方
这个代码 public function info($id) 有点像是 /index/info/{id} 这样的路径识别; ?id=xxx 感觉要另外使用get 获取
curl 127.0.0.1:9501/index/info
{"code":500,"message":"Call to a member function info() on null"} 为什么找不到这个方法呢
使用这个命令启动 composer dump-autoload -o && php bin/hyperf.php start
hyperf 3.0
public function info($id)
id一直取不到
看下你的路由是配置的还是通过AutoController注解定义的
<img src="https://pic2.58cdn.com.cn/nowater/webim/big/n_v2afae0990e0fc48d79f795a87dc320617.png" alt="Snipaste_2023-01-06_19-03-23.png" title="Snipaste_2023-01-06_19-03-23.png" />
如图 echo出来是空的(run可以正常在控制台输出 id确实无法获取 )
$id = (int) $this->request->input('id', 0); 我这边添加了这个
确实是