插件地址:http://m.wtbis.cn/plugin/16
composer require tinywan/exception-handler
config/exception.php
return [
// 這里配置異常處理類
'' => \Tinywan\ExceptionHandler\Handler::class,
];
多應(yīng)用模式時,你可以為每個應(yīng)用單獨(dú)配置異常處理類,參見多應(yīng)用
請求參數(shù)錯誤
use support\Request;
use support\Response;
use Tinywan\ExceptionHandler\Exception\BadRequestHttpException;
class Token{
public function issueToken(Request $request): Response
{
$params = $request->post();
if (empty($params)) {
throw new BadRequestHttpException('賬號或密碼不能為空');
}
}
}
以上異常拋出錯誤信息,如下格式:
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=utf-8
{
"code": 0,
"msg": "賬號或密碼不能為空",
"data": {},
}
所有返回的異常信息將以json格式返回,以上為
返回簡略的異常信息
所有的異常錯誤處理器根據(jù)配置文件 config/app.php
中debug
的值來調(diào)整錯誤顯示, 當(dāng)debug
值為true
(表示在調(diào)試模式), 錯誤處理器會顯示異常以及詳細(xì)的函數(shù)調(diào)用棧和源代碼行數(shù)來幫助調(diào)試,將返回詳細(xì)的異常信息。 當(dāng)debug
值為false
,只有錯誤信息會被顯示以防止應(yīng)用的敏感信息泄漏,將返回簡略的異常信息。
返回詳細(xì)的異常信息
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=utf-8
{
"code": 0,
"msg": "password不允許為空",
"data": {
"request_url": "POST //127.0.0.1:8888/oauth/issue-token",
"timestamp": "2022-03-06 15:19:12",
"client_ip": "172.18.0.1",
"request_param": {
"username": "webman"
},
"error_message": "password不允許為空",
"error_trace": "#0 /var/www/webman-admin/app/functions.php(68): Tinywan\\Validate\\Validate->check(Array)\n#1 /var/www/webman-admin/app/controller/Authentication.php(25): ..."
}
}
自定義一個:405 Method Not Allowed
(表示:請求行中指定的請求方法不能被用于請求相應(yīng)的資源)
自定義異常類只需要繼承Tinywan\ExceptionHandler\Exception\BaseException
類即可
<?php
declare(strict_types=1);
namespace support\exception;
use Tinywan\ExceptionHandler\Exception\BaseException;
class MethodNotAllowedException extends BaseException
{
/**
* @var int
*/
public int $statusCode = 405;
/**
* @var string
*/
public string $errorMessage = '請求行中指定的請求方法不能被用于請求相應(yīng)的資源';
}
use support\Request;
use support\Response;
use support\exception\MethodNotAllowedException;
class Token{
public function issueToken(Request $request): Response
{
$params = $request->post();
if (empty($params)) {
throw new MethodNotAllowedException();
}
}
}
使用postman請求截圖
ValidateException
JwtTokenException
更多:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
這些額外的信息不需要返回給客戶端,怎么去掉呢
將 buildResponse 返回的data 值給于空值就好了
/**
* @inheritDoc
*/
protected function buildResponse(): Response
{
// 構(gòu)造自己項(xiàng)目下的響應(yīng)
return json([
// 'code' => $this->statusCode, // 使用 statusCode 作為 code 返回
'code' => 500, // 使用 statusCode 作為 code 返回
'msg' => $this->errorMessage,
// 'data' => $this->responseData,
'data' => (object)[],
]);
}
在同時安裝illuminate/events和webman/log的情況下,拋出異常會被webman/log記錄為SQL異常日志,實(shí)際寫入日志是在webman/log插件里寫入
// config/exception.php
return [
// '' => support\ErrorHandler::class,
'' => \Tinywan\ExceptionHandler\Handler::class,
];
// config/log.php
return [
'default' => [
'handlers' => [
[
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
runtime_path() . '/logs/webman.log',
7, //$maxFiles
env('APP_DEBUG', false)?Monolog\Logger::DEBUG : Monolog\Logger::WARNING,
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [null, 'Y-m-d H:i:s', true],
],
],
],
],
];
// 中間件
namespace app\middleware;
class LoginAuth implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
$user_id = JwtToken::getCurrentId();
if ($user_id === 0) {
throw new UnauthorizedHttpException('ID異常');
}
$user = LyUser::where('user_id', $user_id)->first([
'user_id',
'state',
]);
if (!$user) {
throw new UnauthorizedHttpException('用戶不存在');
}
if ($user->state == LyUserStateConstant::LOCK) {
throw new UnauthorizedHttpException('用戶被鎖定');
}
return $next($request);
}
}
日志信息如下
[2024-01-22 19:19:21] default.ERROR: xxx.xx.xxx.xx GET xxxxx.com.cn/talk/lists [10.6711ms] [webman/log]
[SQL] [connection:default] select * from `tb_user` where `tb_user`.`user_id` = 1003190 limit 1 [4.62 ms]
Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException in /data1/services/incoming/app/middleware/LoginAuth.php:45
Stack trace:
#0 /data1/services/incoming/vendor/workerman/webman-framework/src/App.php(341): app\middleware\LoginAuth->process(Object(support\Request), Object(Closure))
#1 /data1/services/incoming/vendor/webman/log/src/Middleware.php(58): Webman\App::Webman\{closure}(Object(support\Request))
#2 /data1/services/incoming/vendor/workerman/webman-framework/src/App.php(341): Webman\Log\Middleware->process(Object(support\Request), Object(Closure))
#3 /data1/services/incoming/vendor/webman/cors/src/CORS.php(12): Webman\App::Webman\{closure}(Object(support\Request))
#4 /data1/services/incoming/vendor/workerman/webman-framework/src/App.php(341): Webman\Cors\CORS->process(Object(support\Request), Object(Closure))
#5 /data1/services/incoming/app/middleware/GlobalLog.php(25): Webman\App::Webman\{closure}(Object(support\Request))
#6 /data1/services/incoming/vendor/workerman/webman-framework/src/App.php(341): app\middleware\GlobalLog->process(Object(support\Request), Object(Closure))
#7 /data1/services/incoming/vendor/workerman/webman-framework/src/App.php(141): Webman\App::Webman\{closure}(Object(support\Request))
#8 /data1/services/incoming/vendor/workerman/workerman/Connection/TcpConnection.php(646): Webman\App->onMessage(Object(Workerman\Connection\TcpConnection), Object(support\Request))
#9 [internal function]: Workerman\Connection\TcpConnection->baseRead(Resource id #14199, 2, Resource id #14199)
#10 /data1/services/incoming/vendor/workerman/workerman/Events/Event.php(193): EventBase->loop()
#11 /data1/services/incoming/vendor/workerman/workerman/Worker.php(1635): Workerman\Events\Event->loop()
#12 /data1/services/incoming/vendor/workerman/workerman/Worker.php(1426): Workerman\Worker::forkOneWorkerForLinux(Object(Workerman\Worker))
#13 /data1/services/incoming/vendor/workerman/workerman/Worker.php(1400): Workerman\Worker::forkWorkersForLinux()
#14 /data1/services/incoming/vendor/workerman/workerman/Worker.php(560): Workerman\Worker::forkWorkers()
#15 /data1/services/incoming/vendor/workerman/webman-framework/src/support/App.php(131): Workerman\Worker::runAll()
#16 /data1/services/incoming/start.php(4): support\App::run()
#17 {main}
[] []
目前處理方式是
config/plugin/webman/log/app.php
return [
'enable' => true,
'exception' => [
// 是否記錄異常到日志
'enable' => true,
// 不會記錄到日志的異常類
'dontReport' => [
support\exception\BusinessException::class,
Tinywan\Validate\Exception\ValidateException::class,
Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException::class,
],
],
];
src/Handler.php
文件90行和97行,如果讀不到配置會報錯,建議加上默認(rèn)空數(shù)組值。