正文
Docker构建本地开发环境
使用项目中的Dockerfile文件构建本地环境,项目目录执行如下命令即可:
docker build -t laravel-project -f Dockerfile .
docker run -d --name laravel-project -itv 你的本机项目绝对路径:/var/www/html -p 11081:80 laravel-project
执行成功后,通过 docker ps 检查是否启动成功,如下即为创建成功了,这里宿主机端口为11081
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3732957703e laravel-project "/usr/bin/supervisor…" 2 seconds ago Up 1 second (health: starting) 0.0.0.0:11081->80/tcp, :::11081->80/tcp laravel-project
统一接口响应
因为是提供api服务,开始项目之前先定义接口公共响应结构,在app/Http/Controller/Controller中定义方法如下:
/**
* 接口成功
* @param array $data
* @param string $msg
* @return array
*/
public function apiSuccess(array $data = [], string $msg = 'success'): array
{
return [
'msg' => $msg,
'code' => Constants::API_CODE_SUCCESS,
'data' => $data
];
}
/**
* 接口失败
* @param string $msg
* @param int $code
* @param array $data
* @return array
*/
public function apiFail(string $msg = 'api fail', int $code = Constants::API_CODE_FAIL, array $data = []): array
{
return [
'msg' => $msg,
'code' => $code,
'data' => $data
];
}
/**
* 自定义响应
* @param string $msg
* @param int $code
* @param array $data
* @return array
*/
public function apiResponse(string $msg = '', int $code = 0, array $data = []): array
{
return [
'msg' => $msg,
'code' => $code,
'data' => $data
];
}
我们定义返回体为msg、code、data三个字段,code=200代表成功
新增Controller
php artisan make:controller Api/IndexController
随便加一个方法
public function index()
{
return $this->apiSuccess([
'name'=> 'jack'
]);
}
新增Route
修改routes/api.php,路由的ServiceProvider在app/Providers/RouteServiceProvider.php
Route::namespace("App\Http\Controllers\Api")->prefix("v1")->group(function () {
Route::get("index", [IndexController::class, 'index']);
});
接口参数校验
场景:用户登录 通过api/v1/login 传入username/password完成登录校验,现在没有人在controller里面通过if(empty($username))去校验参数了, 参数校验通过Request完成,主要校验参数值的有效性
php artisan make:request Index/LoginRequest
代码如下
class LoginRequest extends BaseRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'username' => 'required|min:1',
'password' => 'required|min:1'
];
}
public function messages()
{
return [
'username.required' => '用户名不能为空',
'username.min'=> '用户名格式错误',
'password.required' => '密码不能为空',
'password.min'=> '密码格式错误',
];
}
}
在Controller中就可以使用Request进行参数校验了,validated()方法返回校验通过的参数数组
/**
* @param LoginRequest $loginRequest
* @return array
*/
public function login(LoginRequest $loginRequest): array
{
$params = $loginRequest->validated();
return $this->apiSuccess([
'name' => $params['username']
]);
}
这时我们访问api/v1/login如果参数不合法就会通过LoginRequest抛出异常
异常错误正确返回给客户端
默认的错误处理会被渲染到页面展示出来
框架所有的错误被app/Exception/handler.php 捕获后会渲染到客户端,但是我们作为api服务规定通过统一格式返回,因此通过改造app/Exception/handler.php来实现。
handler有两个重要方法,render跟report render用来渲染框架的异常给客户端,report用来提交给系统处理一般是记录到日志中
- 改造render,给客户端返回json异常数据
public function render($request, Throwable $e)
{
if ($e instanceof HttpException) {
$code = $e->getStatusCode();
} else {
$code = $e->getCode() ?: Constants::API_CODE_FAIL;
}
return response()->json([
'msg' => $e->getMessage(),
'code' => $code,
'data' => []
]);
}
通过api/v1/login进行测试
参数校验失败的错误信息
默认情况下Request通过抛出ValidationException 提示参数校验失败,但是我们看不到具体的错误信息,他看起来是这样的,不知道哪个参数不对
- 改造Request,我们把validateException的第一个错误拿出来返回给客户端就可以了
class BaseRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
protected function failedValidation(Validator $validator)
{
$errors = $validator->errors()->all();
throw new HttpException(Constants::API_CODE_FAIL, $errors[0]);
}
}
这样看起来比较清晰了!
记录日志
Laravel使用Monolog来记录日志,由于单个日志文件会很大不方便查看,这里我们的策略是多channel按日期记录日志。
logging 的配置文件在app/config/loggin.php
- 新增channel channel通常根据需求自定义即可,建议根据业务流程来增加,比如下单流程新增一个channel这样方便后期的检索。
这里使用daily_api_index为cahnnel,一共记录30个文件,一天一个。loggin.php
'daily_api_index' => [
'driver' => 'daily',
'path' => '/var/log/application/api.log',
'level' => env('LOG_LEVEL', 'debug'),
'days' => 30,
],
- 使用日志
public function login(LoginRequest $loginRequest): array
{
$params = $loginRequest->validated();
Log::channel("daily_api_index")->info("get-request", [$params]);
return $this->apiSuccess([
'name' => $params['username']
]);
}
日志记录如下所示
/var/log/application $ tail -f daily_api_index-2021-09-10.log
[2021-09-10 03:50:46] local.INFO: get-request [{"username":"jack","password":"jack"}]
总结
这里我们通过新增一个新接口使其能正确访问,并对日志、异常处理、接口响应做了响应的优化。
文末福利
- 代码:github.com/nobody05/la…
- 参考文档:learnku.com/docs/larave…
- 优惠券领取、感谢关注😁