2022年12月17日14:47:22
之前代码一直是使用trait
来处理返回,但是如果遇到不熟悉代码系统设计的人就麻烦了,就想着能不能使用路由中间件来处理所有问题
trait ResponseTrait
{
public function success(mixed $data = '', string $msg = '操作成功')
{
return response()->json(['code' => GlobalCode::SUCCESS, 'msg' => $msg, 'data' => $data]);
}
public function fail(Exception $e, $status = 200, array $headers = [])
{
if (request()->debug == env('DEBUG', GlobalCode::DEBUG) || env('DEBUG') == GlobalCode::DEBUG) {
return response()->json(['code' => GlobalCode::FAIL, 'msg' => $e->getMessage(), 'data' => $e->getTraceAsString()], $status, $headers);
} else {
return response()->json(['code' => GlobalCode::FAIL, 'msg' => $e->getMessage(), 'data' => $e->getMessage()], $status, $headers);
}
}
public function grant(Exception $e)
{
if (request()->debug == env('DEBUG', GlobalCode::DEBUG) || env('DEBUG') == GlobalCode::DEBUG) {
return response()->json(['code' => GlobalCode::GRANT, 'msg' => $e->getMessage(), 'data' => $e->getTraceAsString()]);
} else {
return response()->json(['code' => GlobalCode::GRANT, 'msg' => $e->getMessage(), 'data' => $e->getMessage()]);
}
}
public function successMsg(string $msg = 'success')
{
return response()->json(['code' => GlobalCode::SUCCESS, 'msg' => $msg, 'data' => $msg]);
}
public function failMsg(string|array $msg = 'success')
{
return response()->json(['code' => GlobalCode::FAIL, 'msg' => $msg, 'data' => $msg]);
}
}
控制器调用代码
class IndexController extends Controller
{
use ResponseTrait;
public function login(Request $request)
{
try {
$username = parameterCheck($request->username, 'string', '');
$password = parameterCheck($request->password, 'string', '');
$code = parameterCheck($request->code, 'string', '');
$result = LoginService::login($username, $password, $code);
return $this->success($result, '登录成功');
} catch (Exception $e) {
return $this->fail($e);
}
}
}
改造:新增异常类,用来区分逻辑
GrantException.php RequestLimitException.php 在app/Exceptions/
目录下
class GrantException extends Exception
{
}
class RequestLimitException extends Exception
{
}
新增返回数据处理中间件:ResponseHandle.php response.handle挂在路由中间使用
class ResponseHandle
{
use ResponseTrait;
/**
* Handle an incoming request.
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);
$content = $response->getOriginalContent();
if ($content instanceof GrantException) {
return $this->grant($content);
} elseif ($content instanceof Throwable) {
return $this->fail($content);
} else {
return $this->success($content);
}
}
}
新增返回数据处理中间件:RequestLimit.php request.limit挂在路由中间使用
class RequestLimit
{
use ResponseTrait;
/**
* Handle an incoming request.
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);
$request_ip = request()->ip() == '127.0.0.1' ? request()->header('x-real-ip', '127.0.0.1') : request()->ip();
$key = 'admin_login:' . sha1(request()->getHost() . '|' . $request_ip); //针对域名+ip
// $key = 'admin_login:' . sha1(request()->getHost() . '|' . request()->input('username') . '|' . $request_ip);//针对域名+用户名+ip
// $key = 'admin_login:' . sha1(request()->getHost() . '|' . request()->getPathInfo() . '|' . $request_ip);//针对域名+路由+ip
// if ($content instanceof RequestLimitException) {
if ($response->getOriginalContent() instanceof Throwable) {
$exists = Redis::exists($key);
if ($exists) {
$times = Redis::get($key);
Redis::setex($key, 3600, (int)$times + 1);
} else {
Redis::setex($key, 3600, 1);
}
$times = Redis::get($key);
if ((int)$times > 5) {
return $response->setContent(new Exception('错误登录超过5次'));
}
} else {
Redis::del($key);
}
return $response;
}
}
这样好处是统一处理,避免不懂你代码结构设计的人,胡乱写
也方便以后代码维护
Route::get('/test', [\App\Http\Controllers\Open\TestController::class, 'index'])->middleware(['response.handle', 'request.limit']); //测试接口
注意:因为response.handle
里有返回处理,这两个中间的顺序是固定的
因为执行顺序是response.handle
在前,但是如果把response.handle
的位置放在后面就会出现问题,混用的时候,先测试一下中间的顺序
或者在改造的一下response.handle
方便到处使用