基于Django实现FinTS客户端多步骤交互的架构设计咨询
生产级FinTS Django客户端架构设计与问题解决方案
一、现有问题的针对性修复
1. 视图向BackgroundWorker发消息触发Redis类型错误
问题核心是Channels BackgroundWorker传递的消息必须是Redis可序列化的基础类型(字符串、数字、字典、列表),不能直接传递FinTS3PinTanClient这类复杂对象。
解决办法:
- 视图层仅传递状态标识信息(如用户ID、会话ID、唯一任务ID),而非对象实例。
- BackgroundWorker通过标识从存储介质(Redis/数据库)中读取序列化后的客户端状态,再反序列化为
FinTS3PinTanClient实例。 - 示例代码思路:
# 视图中发送消息 channel_layer.send("background_worker", { "type": "process.fints", "user_id": request.user.id, "session_key": request.session.session_key }) # Worker中处理 def process_fints(self, event): session_key = event["session_key"] serialized_state = redis_client.get(f"fints_client:{session_key}") client = FinTS3PinTanClient.deserialize(serialized_state) # 后续操作
2. FinTS3PinTanClient对象状态丢失
利用库的序列化能力,将状态持久化到Redis或Django数据库:
- Redis选型:适合临时状态存储,用库自带的序列化方法把状态转成字符串,以用户会话ID/任务ID为键存储,设置30分钟左右的过期时间(覆盖TAN输入的常见超时窗口)。
- 数据库选型:若需长期留存操作记录,新建
FintsClientSession模型:from django.db import models from django.contrib.auth.models import User class FintsClientSession(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) session_id = models.CharField(max_length=255, unique=True) serialized_state = models.TextField() created_at = models.DateTimeField(auto_now_add=True) expires_at = models.DateTimeField() - 操作流程:初始化客户端后立即序列化存储,Worker每次处理前读取反序列化,操作完成后重新序列化更新存储。
二、架构方案选型:混合方案优于纯WebSocket
纯WebSocket的局限性
FinTS的4步流程中,连接、请求TAN是耗时IO操作,纯WebSocket会长期占用连接资源;生产环境中WebSocket连接数有限,高并发场景下易出现资源瓶颈。
推荐生产级架构:Django表单 + Celery(替代BackgroundWorker) + WebSocket
BackgroundWorker适合轻量异步任务,生产级更推荐Celery做任务调度,整体流程如下:
- 凭证输入:用Django表单处理银行账号、PIN等敏感信息(HTTP POST提交,利用Django的CSRF防护、表单验证,比WebSocket更安全)。
- 异步初始化与TAN请求:
- 表单提交后,生成唯一
task_id,将用户凭证、task_id存入Redis,启动Celery任务。 - Celery任务初始化
FinTS3PinTanClient,完成连接并请求TAN,序列化状态到Redis,通过WebSocket向前端推送“等待TAN输入”消息(附带task_id)。
- 表单提交后,生成唯一
- TAN提交与交易获取:
- 前端展示TAN输入框,用户输入后通过WebSocket发送
task_id和TAN到后端。 - WebSocket消费者读取Redis中的序列化状态,反序列化为客户端实例,提交TAN并获取交易数据,完成后清理或更新状态。
- 通过WebSocket将交易结果推送给前端。
- 前端展示TAN输入框,用户输入后通过WebSocket发送
三、生产级优化要点
- 安全防护:
- 敏感信息传输强制HTTPS/WSS,Redis存储序列化状态时用
cryptography加密,防止数据泄露。 task_id与用户身份绑定,校验请求合法性,避免越权。
- 敏感信息传输强制HTTPS/WSS,Redis存储序列化状态时用
- 错误处理:
- Celery任务添加重试机制(
autoretry_for=(ConnectionError,)),重试次数设为2-3次。 - 前端处理超时场景(如TAN请求超时),提供重试入口。
- Celery任务添加重试机制(
- 资源清理:
- Redis状态设置过期时间,用Celery Beat定时清理过期的
FintsClientSession记录。 - WebSocket断开后标记任务过期,终止无效处理。
- Redis状态设置过期时间,用Celery Beat定时清理过期的
- 监控日志:
- 对FinTS每一步操作打日志,包含
task_id、用户ID、操作结果,便于排查问题。 - 监控Celery任务成功率、Redis内存、WebSocket连接数,设置告警。
- 对FinTS每一步操作打日志,包含
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

