337 lines
8.4 KiB
Markdown
337 lines
8.4 KiB
Markdown
# 第四章 架构设计 - 请求处理流程
|
||
|
||
## 4.1 请求处理全链路
|
||
|
||
一个完整的 HTTP 请求在 系统中的处理流程如下:
|
||
|
||
```
|
||
浏览器
|
||
|
|
||
| (1) 发起HTTP请求 (携带 Authorization: Bearer <token>)
|
||
v
|
||
Nginx
|
||
|
|
||
| (2) 反向代理,静态资源由Nginx处理,API请求转发到Django
|
||
v
|
||
Django WSGI
|
||
|
|
||
| (3) 进入中间件链
|
||
v
|
||
CORS中间件 (corsheaders.middleware.CorsMiddleware)
|
||
|
|
||
| (4) 处理跨域请求,添加CORS响应头
|
||
v
|
||
check_login装饰器 (middleware/login_middleware.py)
|
||
|
|
||
| (5) 验证JWT token有效性
|
||
v
|
||
URL路由匹配 (application/urls.py)
|
||
|
|
||
| (6) 根据URL分发到对应视图类
|
||
v
|
||
PermissionRequired混入类 (middleware/permission_middleware.py)
|
||
|
|
||
| (7) 验证用户权限节点
|
||
v
|
||
View视图类 (views.py)
|
||
|
|
||
| (8) 解析请求参数,调用Service
|
||
v
|
||
Service服务函数 (services.py)
|
||
|
|
||
| (9) 执行业务逻辑,操作数据库
|
||
v
|
||
R.ok()/R.failed() (utils/R.py)
|
||
|
|
||
| (10) 构造统一JSON响应
|
||
v
|
||
JsonResponse
|
||
|
|
||
| (11) 返回响应数据
|
||
v
|
||
浏览器
|
||
```
|
||
|
||
## 4.2 中间件处理顺序
|
||
|
||
根据 `application/settings.py` 的配置,中间件按以下顺序执行:
|
||
|
||
```python
|
||
MIDDLEWARE = [
|
||
'corsheaders.middleware.CorsMiddleware', # 1. CORS跨域处理
|
||
'django.middleware.security.SecurityMiddleware', # 2. 安全处理
|
||
'django.contrib.sessions.middleware.SessionMiddleware', # 3. Session处理
|
||
'django.middleware.common.CommonMiddleware', # 4. 通用处理
|
||
# 'django.middleware.csrf.CsrfViewMiddleware', # CSRF已禁用(使用JWT)
|
||
'django.contrib.auth.middleware.AuthenticationMiddleware', # 5. 认证处理
|
||
'django.contrib.messages.middleware.MessageMiddleware', # 6. 消息处理
|
||
'django.middleware.clickjacking.XFrameOptionsMiddleware', # 7. 点击劫持防护
|
||
]
|
||
```
|
||
|
||
**注意**:`check_login` 和 `PermissionRequired` 不是 Django 中间件,而是通过装饰器和混入类实现的,作用于视图层面。
|
||
|
||
## 4.3 JWT 认证流程
|
||
|
||
### 4.3.1 登录认证
|
||
|
||
```python
|
||
# 1. 用户提交用户名密码
|
||
POST /login
|
||
{
|
||
"username": "admin",
|
||
"password": "123456",
|
||
"captcha": "abc123"
|
||
}
|
||
|
||
# 2. 验证通过后生成JWT Token
|
||
from utils.jwt import create_token
|
||
|
||
payload = {
|
||
'userId': user.id,
|
||
'username': user.username,
|
||
'realname': user.realname
|
||
}
|
||
token = create_token(payload, timeout=20) # 20分钟过期
|
||
|
||
# 3. 返回Token给前端
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
|
||
},
|
||
"msg": "登录成功"
|
||
}
|
||
```
|
||
|
||
### 4.3.2 请求认证
|
||
|
||
```python
|
||
# 1. 前端在请求头中携带Token
|
||
headers = {
|
||
"Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
|
||
}
|
||
|
||
# 2. check_login装饰器验证Token
|
||
def check_login(func):
|
||
def wrapper(request, *args, **kwargs):
|
||
# 忽略不需要认证的URL
|
||
ignoreURL = ['/login', '/captcha']
|
||
if request.path not in ignoreURL:
|
||
# 从请求头获取Token
|
||
access_token = request.headers['Authorization']
|
||
access_token = access_token.replace('Bearer ', "")
|
||
|
||
# 验证Token
|
||
result = parse_payload(access_token)
|
||
if result['code'] != 0:
|
||
return R.failed(code=401, msg=result['msg'])
|
||
|
||
return func(request, *args, **kwargs)
|
||
return wrapper
|
||
```
|
||
|
||
### 4.3.3 Token 黑名单检查
|
||
|
||
```python
|
||
# 1. 验证Token时先检查黑名单
|
||
def parse_payload(token):
|
||
# 检查Token是否在黑名单中
|
||
if is_token_blacklisted(token):
|
||
return {'code': -1, 'msg': 'token已失效,请重新登录'}
|
||
|
||
# 解密验证JWT令牌
|
||
verified_payload = jwt.decode(token, JWT_SALT, algorithms=[JWT_ALGORITHM])
|
||
return {'code': 0, 'data': verified_payload}
|
||
|
||
# 2. 黑名单检查使用Redis
|
||
def is_token_blacklisted(token):
|
||
redis = get_redis_connection("default")
|
||
fingerprint = hashlib.sha256(token.encode('utf-8')).hexdigest()
|
||
key = f'token:blacklist:{fingerprint}'
|
||
return redis.exists(key) > 0
|
||
```
|
||
|
||
## 4.4 权限验证流程
|
||
|
||
### 4.4.1 权限节点定义
|
||
|
||
每个操作对应一个权限节点,格式为 `sys:<module>:<action>`:
|
||
|
||
```python
|
||
# 示例:案例模块的权限节点
|
||
permission_required = ("sys:example:page",) # 分页查询
|
||
permission_required = ("sys:example:detail",) # 详情查询
|
||
permission_required = ("sys:example:add",) # 添加
|
||
permission_required = ("sys:example:update",) # 更新
|
||
permission_required = ("sys:example:delete",) # 删除
|
||
permission_required = ("sys:example:status",) # 状态更新
|
||
```
|
||
|
||
### 4.4.2 权限验证逻辑
|
||
|
||
```python
|
||
class PermissionRequired(PermissionRequiredMixin):
|
||
def has_permission(self):
|
||
# 获取所需权限节点
|
||
permissions = self.get_permission_required()
|
||
|
||
# 获取当前用户ID
|
||
user_id = get_user_id(self.request)
|
||
|
||
# 超级管理员(ID=1)自动放行
|
||
if user_id and user_id != 1:
|
||
# 获取用户权限列表
|
||
permission_list = services.get_user_permissions(user_id)
|
||
|
||
# 检查是否拥有所需权限
|
||
for permission in permissions:
|
||
if permission not in permission_list:
|
||
return False
|
||
|
||
return True
|
||
```
|
||
|
||
### 4.4.3 权限获取逻辑
|
||
|
||
```python
|
||
# application/menu/services.py
|
||
def get_user_permissions(user_id):
|
||
if user_id == 1:
|
||
# 超级管理员拥有所有权限
|
||
menu_list = Menu.objects.filter(is_delete=False, type=1, status=0).values()
|
||
return [item['permission'] for item in menu_list]
|
||
else:
|
||
# 普通用户从角色关联中获取权限
|
||
sql = '''
|
||
SELECT m.* FROM django_menu AS m
|
||
INNER JOIN django_role_menu AS rm ON m.id=rm.menu_id
|
||
INNER JOIN django_user_role AS ur ON ur.role_id=rm.role_id
|
||
WHERE ur.user_id=%s AND (m.type=1 OR (m.type=0 AND m.permission!=''))
|
||
AND m.status=0 AND m.is_delete=0
|
||
'''
|
||
menu_list = Menu.objects.raw(sql, [user_id])
|
||
return [item.permission for item in menu_list]
|
||
```
|
||
|
||
## 4.5 业务处理流程
|
||
|
||
以"添加案例"为例,完整的业务处理流程:
|
||
|
||
```
|
||
1. View层 (ExampleAddView.post)
|
||
+-- 检查演示模式 (DJANGO_DEMO)
|
||
+-- 调用 Service: services.add_example(request)
|
||
|
||
2. Service层 (add_example)
|
||
+-- 解析请求体: parse_request_body(request)
|
||
+-- 表单验证: forms.ExampleForm(data)
|
||
+-- 处理文件: save_file(avatar, "example")
|
||
+-- 创建记录: Example.objects.create(...)
|
||
+-- 返回结果: R.ok(msg="创建成功")
|
||
|
||
3. Model层 (Example)
|
||
+-- Django ORM 生成 SQL
|
||
+-- MySQL 执行 INSERT
|
||
+-- 自动生成 create_time、update_time
|
||
```
|
||
|
||
## 4.6 响应格式规范
|
||
|
||
所有 API 接口返回统一的 JSON 格式:
|
||
|
||
### 成功响应
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"id": 1,
|
||
"name": "案例名称",
|
||
"status": 1
|
||
},
|
||
"msg": "操作成功",
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
### 分页响应
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"records": [
|
||
{"id": 1, "name": "案例1"},
|
||
{"id": 2, "name": "案例2"}
|
||
],
|
||
"total": 100,
|
||
"size": 10,
|
||
"current": 1,
|
||
"pages": 10
|
||
},
|
||
"msg": "操作成功",
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
### 失败响应
|
||
|
||
```json
|
||
{
|
||
"code": 1,
|
||
"data": null,
|
||
"msg": "操作失败",
|
||
"ok": false
|
||
}
|
||
```
|
||
|
||
### 认证失败响应
|
||
|
||
```json
|
||
{
|
||
"code": 401,
|
||
"data": null,
|
||
"msg": "token已失效,请重新登录",
|
||
"ok": false
|
||
}
|
||
```
|
||
|
||
## 4.7 异常处理机制
|
||
|
||
### 4.7.1 全局异常处理
|
||
|
||
```python
|
||
# Service层统一使用 try-except 捕获异常
|
||
def add_example(request):
|
||
try:
|
||
# 业务逻辑
|
||
Example.objects.create(...)
|
||
return R.ok(msg="创建成功")
|
||
except Exception as e:
|
||
logging.error(f"添加案例异常: {str(e)}")
|
||
return R.failed(msg="添加失败,请稍后重试")
|
||
```
|
||
|
||
### 4.7.2 表单验证异常
|
||
|
||
```python
|
||
# 表单验证失败时返回具体错误信息
|
||
form = ExampleForm(data)
|
||
if not form.is_valid():
|
||
return R.failed(msg=regular.get_err(form))
|
||
```
|
||
|
||
### 4.7.3 数据库异常
|
||
|
||
```python
|
||
# 数据库操作异常被捕获并返回友好提示
|
||
try:
|
||
instance.save()
|
||
except IntegrityError as e:
|
||
return R.failed(msg="数据完整性错误")
|
||
except Exception as e:
|
||
logging.error(f"数据库异常: {str(e)}")
|
||
return R.failed(msg="操作失败,请稍后重试")
|
||
```
|