Summary of custom exception handling in the project error page & API error
Preface
Generally, routing in a project is divided into return 模板引擎页面
and return api接口json数据
. The two methods require different content to be returned. If the template engine page encounters an exception, it needs to return an error page. If the api interface encounters an exception, it needs to return json data.
The development mode and the online mode should return different content. The development mode should return as much specific error information as possible, while the online mode cannot return specific error messages. Generally, it displays a friendly prompt like "Server error, please try again later". Instead of displaying a bunch of error codes (both unfriendly and unsafe).
If there is a better way, comments are welcome.
1. Anomaly classification
1. The controller cannot be found
When accessing the route, if the controller is wrong, you need to use 空控制器
interception to report errors.
2. Method not found
The method cannot be found to modify the BaseController controller in the app directory to override the __call method.
3. The requested resource does not exist
To customize the interception of error messages, you can use Provider to customize the error handling class, override the render method, and return different data according to different errors.
4. System internal exception, HTTP exception, etc.
The third point.
Two, exception handling
1. Pre-processing
(1) The
.env
file definitionAPP_DEBUG
distinguishes between development mode and online mode, true means development mode, false means online mode:
APP_DEBUG = true
(2)
app/common.php
Define theapi
returned data format in the file :
function show($status, $message = 'error', $data = [], $httpStatus = 200){
$result = [
"status" => $status,
"message" => $message,
"result" => $data
];
return json($result, $httpStatus);
}
(3) Create a new provider.php under the current application and specify a custom exception handling class:
<?php
// 容器Provider定义文件
return [
'think\exception\Handle' => 'app\\admin\\exception\\Http',
];
(4) To define the status code configuration, you can add the corresponding status code configuration
config
under the folderstatus.php
:
<?php
return [
"success" => 1,
"error" => 0,
"http_status" => [
"not_found" => 404,
"validate_error" => 422,
"internal_error" => 500
]
];
(5) Prepare error pages (404, 500, etc.)
2. Exception handling detailed code
(1) The controller cannot be found
app/controller
Create a new Error
class in the directory ( 文件名固定为Error
):
这里需要注意的是,多应用的控制器应该定义在应用文件夹里,这里定义在app目录是为了作用于app下全部应用。
<?php
namespace app\controller;
class Error
{
public function __call($name, $arguments)
{
if(request()->isAjax()){
return show(config("status.error"), env('app_debug') ? "控制器{
$name}找不到" : '当前请求资源不存在,请稍后再试', [], config("status.http_status.not_found"));
}else{
return view(root_path() . 'public/error/admin/404.html', ['e' => env('app_debug') ? "控制器{
$name}找不到" : '当前请求资源不存在,请稍后再试'], config("status.http_status.not_found"));
}
}
}
(2) Method not found
In app/BaseController.php
adding the controller __call
method:
public function __call($name, $arguments)
{
if(request()->isAjax()){
return show(config("status.error"), env('app_debug') ? "找不到{
$name}方法" : '当前请求资源不存在,请稍后再试', [], config("status.http_status.not_found"));
}else{
return view(root_path() . 'public/error/admin/404.html', ['e' => env('app_debug') ? "{
$name}方法找不到" : '当前请求资源不存在,请稍后再试'], config("status.http_status.not_found"));
}
}
(3) The requested resource does not exist and the system error is abnormal
app\\admin\\exception\\Http
:
<?php
namespace app\admin\exception;
use ErrorException;
use Exception;
use InvalidArgumentException;
use ParseError;
use PDOException;
use think\exception\ClassNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\RouteNotFoundException;
use think\Response;
use Throwable;
use TypeError;
class Http extends Handle
{
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
$returnCode = config("status.error");
$returnMessage = "系统异常,请稍后再试";
$returnData = [];
$httpStatus = 500;
if($e instanceof BusinessException){
// 自定义添加的业务异常
$returnMessage = $e->getMessage();
$httpStatus = config("status.http_status.business_error");
}else if($e instanceof ValidateException){
$returnMessage = $e->getError();
$httpStatus = config("status.http_status.validate_error");
}else if (($e instanceof ClassNotFoundException || $e instanceof RouteNotFoundException) || ($e instanceof HttpException && $e->getStatusCode() == 404)) {
$returnMessage = env('app_debug') ? $e->getMessage() : '当前请求资源不存在,请稍后再试';
$httpStatus = config("status.http_status.not_found");
}else if ($e instanceof Exception || $e instanceof PDOException || $e instanceof InvalidArgumentException || $e instanceof ErrorException || $e instanceof ParseError || $e instanceof TypeError || ($e instanceof HttpException && $e->getStatusCode() == 500)) {
$returnMessage = env('app_debug') ? $e->getMessage() : '系统异常,请稍后再试';
$httpStatus = config("status.http_status.internal_error");
}
if(request()->isAjax()){
return show($returnCode, $returnMessage, $returnData, $httpStatus);
}else{
if($httpStatus == config("status.http_status.not_found")){
$errorUrl = 'public/error/admin/404.html';
}else{
$errorUrl = 'public/error/admin/error.html';
}
return view(root_path() . $errorUrl, ['e'=>$returnMessage], $httpStatus);
}
}
}
The error information returned in the above code e
needs to be displayed on the error page (404, error):
<p class="error-message">{$e ?? ''}</p>
Three, anomaly detection
Anomaly detection points browser 页面访问异常
and api接口返回异常
also need to check 开发模式
and 线上模式
.
- Controller does not exist
- Method does not exist
- Actively throw an exception
- The system throws an exception
Tips:
api
Interface You can usePostman
the tool simulation, addHeaders
:
Content-Type
asapplication/x-www-form-urlencoded
X-Requested-With
isxmlhttprequest
(The bloggers are lazy and won’t post screenshots, but they’ve tested them all, comrades try it out for yourself, let’s post one after all)