异常处理器
在 Hyperf
里,业务代码都运行在 Worker进程
上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 Worker进程
被中断退出,虽然被中断的 Worker进程
仍会被重新拉起,但对服务而言也是不能接受的,且捕获异常并输出合理的报错内容给客户端也是更加友好的。
我们可以通过对各个 server
定义不同的 异常处理器(ExceptionHandler)
,一旦业务流程存在没有捕获的异常,都会被传递到已注册的 异常处理器(ExceptionHandler)
去处理。
关于,如何自定义异常,如何注册异常,这里就不粘贴了,详细的直接看 Hyperf
文档。 下面,贴合一个实际例子讲解下,如何处理异常。
安装
composer require phper666/jwt-auth:~2.0.1
发布配置
php bin/hyperf.php jwt:publish --config
配置 .env
# 务必改为你自己的字符串
JWT_SECRET=hyperf
#token过期时间,单位为秒
JWT_TTL=60
使用
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use \Phper666\JwtAuth\Jwt;
/**
* @AutoController()
* Class IndexController
* @package App\Controller
*/
class IndexController extends AbstractController
{
/**
* @Inject()
* @var Jwt
*/
protected $jwt;
# 模拟登录
public function login()
{
$username = $this->request->input('username');
$password = $this->request->input('password');
if ($username && $password) {
$userData = [
'uid' => 1, // 如果使用单点登录,必须存在配置文件中的sso_key的值,一般设置为用户的id
'username' => 'xx',
];
$token = $this->jwt->getToken($userData);
$data = [
'code' => 0,
'msg' => 'success',
'data' => [
'token' => (string)$token,
'exp' => $this->jwt->getTTL(),
]
];
return $this->response->json($data);
}
return $this->response->json(['code' => 0, 'msg' => '登录失败', 'data' => []]);
}
# 刷新token,http头部必须携带token才能访问的路由
public function refreshToken()
{
$token = $this->jwt->refreshToken();
$data = [
'code' => 0,
'msg' => 'success',
'data' => [
'token' => (string)$token,
'exp' => $this->jwt->getTTL(),
]
];
return $this->response->json($data);
}
# 注销token,http头部必须携带token才能访问的路由
public function logout()
{
$this->jwt->logout();
return true;
}
# http头部必须携带token才能访问的路由
public function getData()
{
$data = [
'code' => 0,
'msg' => 'success',
'data' => [
'cache_time' => $this->jwt->getTokenDynamicCacheTime() // 获取token的有效时间,动态的
]
];
return $this->response->json($data);
}
public function index()
{
$user = $this->request->input('user', 'Hyperf');
$method = $this->request->getMethod();
return [
'method' => $method,
'message' => "Hello {$user}.",
];
}
}
验证
编辑路由文件
Router::addGroup('/v1', function () {
Router::get('/data', 'App\Controller\IndexController@getData');
}, ['middleware' => [Phper666\JwtAuth\Middleware\JwtAuthMiddleware::class]]);
测试
请求 登陆,返回 token
正常情况下,token 有效、并且正确传入:
那么如果不传递 token、或者 token 失效,jwt-auth
这个组件只是抛出了异常,并在控制台打印出来,,但是用户并不知情。报出 500 的响应
这样肯定不行哈,所以异常处理这个东西就派上用场了。
我们看到在 vendor/phper666/jwt-auth/src/Exception
会有两个异常类。
自定义异常
接下来我们就自定义一下异常处理
touch app/Exception/Handler/JtwExceptionHandler.php
编辑如下代码,主要捕获的就是 Phper666\JwtAuth\Exception\TokenValidException
类。
<?php
namespace App\Exception\Handler;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Phper666\JwtAuth\Exception\TokenValidException;
use Psr\Http\Message\ResponseInterface;
use Throwable;
class JtwExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response)
{
// 判断被捕获到的异常是希望被捕获的异常
if ($throwable instanceof TokenValidException) {
// 格式化输出
$data = json_encode([
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
], JSON_UNESCAPED_UNICODE);
// 阻止异常冒泡
$this->stopPropagation();
return $response->withStatus(500)->withBody(new SwooleStream($data));
}
// 交给下一个异常处理器
return $response;
// 或者不做处理直接屏蔽异常
}
/**
* 判断该异常处理器是否要对该异常进行处理
* @param Throwable $throwable
* @return bool
*/
public function isValid(Throwable $throwable): bool
{
return true;
}
}
注册异常
编辑配置文件 config/autoload/exceptions.php
<?php
declare(strict_types=1);
use Hyperf\Validation\ValidationExceptionHandler;
return [
'handler' => [
'http' => [
App\Exception\Handler\AppExceptionHandler::class,
\App\Exception\Handler\JtwExceptionHandler::class,
],
],
];
然后在测试一下
ok,这就是关于异常的处理。
关于极客返利
极客返利 是由我个人开发的一款网课返利、返现平台。包含 极客时间返现、拉勾教育返现、掘金小册返现、GitChat返现。目前仅包含这几个平台。后续如果有需要可以考虑其他平台。 简而言之就是:你买课,我返现。让你花更少的钱,就可以买到课程。
版权许可
本作品采用 知识共享署名 4.0 国际许可协议 进行许可。转载无需与我联系,但须注明出处,注明文章来源 Hyperf 初体验-异常处理器