Laravel API 开发学习笔记

本文记录 Laravel API 开发的核心知识点,涵盖认证、数据库关系、中间件、API 资源、分页、表单验证、异常处理等模块。

一、Sanctum 认证系统

1.1 Token 格式理解

Token 格式为 1|abc123...

  • 1 = personal_access_tokens 表的 ID
  • abc123... = 明文 token(客户端保存)
  • 数据库只存哈希值 hash('sha256', 'abc123...')

1.2 验证流程

1
2
3
4
5
6
7
客户端发送:1|abc123...

框架解析:id=1, plainText=abc123...

查数据库:SELECT * FROM personal_access_tokens WHERE id=1

比对哈希:hash('sha256', 'abc123...') === 数据库的 token?

1.3 核心代码

注册:

1
2
3
4
5
$user = User::create([
'username' => $validated['username'],
'password' => $validated['password'], // Model 自动哈希
]);
$token = $user->createToken('api')->plainTextToken;

登录:

1
2
3
4
if (!Auth::attempt($credentials)) {
return ['message' => '用户名或密码错误'];
}
$token = $request->user()->createToken('api')->plainTextToken;

登出(当前设备):

1
$request->user()->currentAccessToken()->delete();

登出(所有设备):

1
$request->user()->tokens()->delete();

1.4 路由保护

1
2
3
Route::middleware('auth:sanctum')->group(function () {
Route::post('/messages', [MessageController::class, 'store']);
});

1.5 获取当前用户

1
$request->user()->id

1.6 关键点

要点 说明
密码哈希 Model 的 $casts = ['password' => 'hashed'] 自动处理
Token 返回 $token->plainTextToken(不是 $token
多设备 每个设备独立 token,登出只删当前设备
哈希存储 数据库不存明文,防止泄露后被直接使用

二、数据库关系

2.1 一对多关系

User Model:

1
2
3
4
public function messages()
{
return $this->hasMany(Message::class);
}

Message Model:

1
2
3
4
public function user()
{
return $this->belongsTo(User::class);
}

2.2 预加载(避免 N+1)

1
2
3
4
5
6
7
8
// 不用预加载(N+1 问题)
$messages = Message::all();
foreach ($messages as $message) {
$message->user; // 每条留言都查一次用户
}

// 用预加载(只查 2 次)
$messages = Message::with('user')->get();

2.3 关联用户

数据库添加字段:

1
2
3
ALTER TABLE messages ADD COLUMN user_id BIGINT UNSIGNED NULL;
ALTER TABLE messages ADD CONSTRAINT fk_user
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;

创建时自动关联:

1
2
$validated['user_id'] = $request->user()->id;
$message = Message::create($validated);

三、中间件权限控制

3.1 创建中间件

1
php artisan make:middleware CheckMessageOwner

3.2 中间件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public function handle(Request $request, Closure $next): Response
{
$id = $request->query('id');
$message = Message::find($id);

if (!$message) {
return response()->json(['code' => 404, 'msg' => '留言不存在'], 404);
}

if ($message->user_id !== $request->user()->id) {
return response()->json(['code' => 403, 'msg' => '无权删除'], 403);
}

return $next($request);
}

3.3 注册中间件别名(Laravel 11)

1
2
3
4
5
6
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
'check-message-owner' => CheckMessageOwner::class,
]);
})

3.4 路由应用中间件

1
2
Route::delete('/messages', [MessageController::class, 'destroy'])
->middleware('check-message-owner');

四、API 资源

4.1 创建资源类

1
2
php artisan make:resource UserResource
php artisan make:resource MessageResource

4.2 定义返回字段

UserResource:

1
2
3
4
5
6
7
8
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'username' => $this->username,
// 只返回需要的字段,隐藏 email_verified_at、updated_at 等
];
}

MessageResource(嵌套资源):

1
2
3
4
5
6
7
8
9
10
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'content' => $this->content,
'created_at' => $this->created_at,
'user' => new UserResource($this->user), // 嵌套
];
}

4.3 使用资源

单个资源:

1
return new MessageResource($message);

资源集合:

1
return MessageResource::collection($messages);

五、分页

5.1 使用 paginate()

1
$messages = Message::latest()->with('user')->paginate($perPage);

5.2 返回分页数据

1
2
3
4
5
return MessageResource::collection($messages)
->additional([
'code' => 0,
'msg' => 'ok',
]);

5.3 返回结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"data": [...],
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
},
"meta": {
"current_page": 1,
"last_page": 4,
"per_page": 10,
"total": 19
},
"code": 0,
"msg": "ok"
}

5.4 URL 参数

1
GET /api/messages?page=2&per_page=10

六、表单验证类(Form Request)

6.1 创建 Form Request

1
php artisan make:request StoreMessageRequest

6.2 定义验证规则

1
2
3
4
5
6
7
8
9
10
11
12
13
public function authorize(): bool
{
return true; // 允许请求
}

public function rules(): array
{
return [
'name' => 'required|max:20',
'email' => 'nullable|email',
'content' => 'required',
];
}

6.3 Controller 使用

1
2
3
4
5
6
7
public function store(StoreMessageRequest $request)
{
$validated = $request->validated(); // 获取已验证数据
$validated['user_id'] = $request->user()->id;
$message = Message::create($validated);
// ...
}

6.4 对比原生 PHP

原生 PHP Laravel Form Request
Controller 里写验证 独立 Request 类
$request->validate([...]) $request->validated()
规则分散 集中管理
不可复用 可复用

七、异常处理(统一错误格式)

7.1 配置位置

1
2
3
4
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions): void {
// ...
})

7.2 处理验证异常(422)

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Validation\ValidationException;

$exceptions->render(function (ValidationException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'code' => 422,
'msg' => $e->getMessage(),
'errors' => $e->errors(),
], 422);
}
});

7.3 处理认证异常(401)

1
2
3
4
5
6
7
8
9
10
use Illuminate\Auth\AuthenticationException;

$exceptions->render(function (AuthenticationException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'code' => 401,
'msg' => '无权限访问',
], 401);
}
});

7.4 统一错误格式

错误类型 返回格式 HTTP 状态码
验证失败 {"code":422,"msg":"...","errors":{...}} 422
未登录 {"code":401,"msg":"无权限访问"} 401
无权限 {"code":403,"msg":"无权删除"} 403
资源不存在 {"code":404,"msg":"留言不存在"} 404

八、常用命令汇总

命令 用途
php artisan make:request XxxRequest 创建表单验证类
php artisan make:middleware XxxMiddleware 创建中间件
php artisan make:resource XxxResource 创建 API 资源
php artisan test 运行测试
php artisan vendor/bin/pint 修复代码风格
php artisan migrate 执行迁移
php artisan migrate:rollback 回滚迁移
php artisan tinker REPL 交互环境

九、对比原生 PHP

功能 原生 PHP Laravel
Token 生成 bin2hex(random_bytes(32)) $user->createToken('api')
Token 验证 手写 SQL 查询比对 auth:sanctum 中间件
关系查询 手写 JOIN SQL with('user') 预加载
验证规则 手写 if 判断 Form Request 类
分页 手写 LIMIT + COUNT paginate() 自动处理
错误处理 各种格式混用 统一 JSON 格式

十、项目文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
learn-laravel/
├── app/
│ ├── Http/
│ │ ├── Controllers/ # 业务逻辑
│ │ ├── Middleware/ # 中间件
│ │ ├── Requests/ # 表单验证类
│ │ └── Resources/ # API 资源
│ └── Models/ # Eloquent Model
├── bootstrap/
│ └── app.php # 异常处理配置
├── routes/
│ └── api.php # API 路由
└── database/
└── migrations/ # 数据库迁移

参考资料