一青扔、版本介紹
PS C:\phpstudy_pro\WWW\api.demo.test> php artisan --version
Laravel Framework 10.40.0
PS C:\phpstudy_pro\WWW\api.demo.test>
二、希望情況
-
希望正常情況翩伪,返回:
即:統(tǒng)一http狀態(tài)為200微猖,采用自定義code、message缘屹、data方式實(shí)現(xiàn)凛剥。
{
"code": 200,
"message": "請(qǐng)求成功",
"data": {
"token": "125|tZmR9SOUq946dwxdRM7hlrvvGDOnnmeUaA63MYiv3519f747"
}
}
- 不希望異常情況返回
雖然加了"X-Requested-With":"XMLHttpRequest"
請(qǐng)求頭,可以避免返回html頁面的錯(cuò)誤轻姿,這樣瀏覽器請(qǐng)求時(shí)犁珠,可以快速定位錯(cuò)誤逻炊。但是,這樣返回的數(shù)據(jù)盲憎,狀態(tài)碼依然是http的嗅骄,不是自定義的,碰到有些需要自定義認(rèn)證的異常消息時(shí)饼疙,接口總是不一致溺森,前端處理起來非常麻煩,因此統(tǒng)一一下窑眯。
{
"message": "Device name 不能為空屏积。",
"errors": {
"device_name": [
"Device name 不能為空。"
]
}
}
-
或者希望這樣的錯(cuò)誤保持原樣磅甩。有利于開發(fā)過程中排查錯(cuò)誤炊林。
{
"message": "The GET method is not supported for route api/user/token. Supported methods: POST.",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException",
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\AbstractRouteCollection.php",
"line": 122,
"trace": [
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\AbstractRouteCollection.php",
"line": 107,
"function": "requestMethodNotAllowed",
"class": "Illuminate\\Routing\\AbstractRouteCollection",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\AbstractRouteCollection.php",
"line": 41,
"function": "getRouteForMethods",
"class": "Illuminate\\Routing\\AbstractRouteCollection",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\RouteCollection.php",
"line": 162,
"function": "handleMatchedRoute",
"class": "Illuminate\\Routing\\AbstractRouteCollection",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 761,
"function": "match",
"class": "Illuminate\\Routing\\RouteCollection",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 748,
"function": "findRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php",
"line": 737,
"function": "dispatchToRoute",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 200,
"function": "dispatch",
"class": "Illuminate\\Routing\\Router",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 144,
"function": "Illuminate\\Foundation\\Http\\{closure}",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull.php",
"line": 31,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php",
"line": 21,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php",
"line": 40,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\TrimStrings",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php",
"line": 27,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php",
"line": 99,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php",
"line": 62,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Http\\Middleware\\HandleCors",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php",
"line": 39,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 183,
"function": "handle",
"class": "Illuminate\\Http\\Middleware\\TrustProxies",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php",
"line": 119,
"function": "Illuminate\\Pipeline\\{closure}",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 175,
"function": "then",
"class": "Illuminate\\Pipeline\\Pipeline",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php",
"line": 144,
"function": "sendRequestThroughRouter",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
},
{
"file": "C:\\phpstudy_pro\\WWW\\api.demo.test\\public\\index.php",
"line": 51,
"function": "handle",
"class": "Illuminate\\Foundation\\Http\\Kernel",
"type": "->"
}
]
}
三、實(shí)現(xiàn)處理
- 添加異常處理類
PS C:\phpstudy_pro\WWW\api.demo.test> php artisan make:exception ApiException
INFO Exception [C:\phpstudy_pro\WWW\api.demo.test\app\Exceptions\ApiException.php] created successfully.
修改ApiException.php
<?php
namespace App\Exceptions;
use Exception;
class ApiException extends Exception
{
public function __construct(string $message = "", int $code = 422, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
public function render()
{
return response()->json([
'code' => $this->code ?? 422,
'message' => $this->message,
]);
}
}
測試效果:
{
"code": 422,
"message": "用戶名或密碼不正確!"
}
一般情況卷要,都可以使用throw new ApiException('用戶名或密碼不正確!');
的形式進(jìn)行處理渣聚。但是系統(tǒng)的ValidationException
就不能處理了,那么能不能統(tǒng)一一下呢僧叉?當(dāng)然可以奕枝。重寫 public function render($request, Throwable $e)
即可。
<?php
namespace App\Exceptions;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Routing\Router;
use Illuminate\Validation\ValidationException;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* The list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (Throwable $e) {
//
});
}
/**
* 重寫render實(shí)現(xiàn)
* @param $request
* @param Throwable $e
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|mixed|\Symfony\Component\HttpFoundation\Response
* @throws ApiException
* @throws \ReflectionException
*/
public function render($request, Throwable $e)
{
if ($e instanceof ValidationException) {// 處理驗(yàn)證異常信息
throw new ApiException($e->getMessage(), $e->status);
} else {// 保持原來的實(shí)現(xiàn)
$e = $this->mapException($e);
if (method_exists($e, 'render') && $response = $e->render($request)) {
return Router::toResponse($request, $response);
}
if ($e instanceof Responsable) {
return $e->toResponse($request);
}
$e = $this->prepareException($e);
if ($response = $this->renderViaCallbacks($request, $e)) {
return $response;
}
return match (true) {
$e instanceof HttpResponseException => $e->getResponse(),
$e instanceof AuthenticationException => $this->unauthenticated($request, $e),
$e instanceof ValidationException => $this->convertValidationExceptionToResponse($e, $request),
default => $this->renderExceptionResponse($request, $e),
};
}
}
}
實(shí)現(xiàn)效果:
有處理部分
不處理部分:
- 總結(jié):
1.新增ApiException.php
php artisan make:exception ApiException
并實(shí)現(xiàn)如下:
<?php
namespace App\Exceptions;
use Exception;
class ApiException extends Exception
{
public function __construct(string $message = "", int $code = 422, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
public function render()
{
return response()->json([
'code' => $this->code ?? 422,
'message' => $this->message,
]);
}
}
2.修改Exceptions 下的Handler.php
/**
* 重寫render實(shí)現(xiàn)
* @param $request
* @param Throwable $e
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|mixed|\Symfony\Component\HttpFoundation\Response
* @throws ApiException
* @throws \ReflectionException
*/
public function render($request, Throwable $e)
{
if ($request->ajax() && $e instanceof ValidationException) {// 處理驗(yàn)證異常信息
throw new ApiException($e->getMessage(), $e->status);
} else {// 保持原來的實(shí)現(xiàn)
$e = $this->mapException($e);
if (method_exists($e, 'render') && $response = $e->render($request)) {
return Router::toResponse($request, $response);
}
if ($e instanceof Responsable) {
return $e->toResponse($request);
}
$e = $this->prepareException($e);
if ($response = $this->renderViaCallbacks($request, $e)) {
return $response;
}
return match (true) {
$e instanceof HttpResponseException => $e->getResponse(),
$e instanceof AuthenticationException => $this->unauthenticated($request, $e),
$e instanceof ValidationException => $this->convertValidationExceptionToResponse($e, $request),
default => $this->renderExceptionResponse($request, $e),
};
}
}
至此瓶堕,處理完畢隘道。