FitMall-运动优选项目博客
FitMall 运动优选一个完整健身电商平台的技术全解析从零搭建的全栈健身电商平台涵盖商品交易、AI 智能助手、社区互动、训练管理四大核心模块。本文将拆解其技术选型、架构设计、关键实现细节与工程经验。目录项目概览技术栈一览架构设计那些有意思的技术细节HTTP-Only Cookie 会话认证用 Redis 替代 JWT手搓 Snowflake 分布式 ID 生成器双通道 ES 同步直写 消息队列兜底IK 分词器的双分析器策略AI 三端架构与优雅降级Dify Chatflow 工作流从意图识别到商品推荐订单超时取消与 Redis 分布式锁运行时数据库迁移WebSocket 实时聊天与在线状态追踪总结与思考1.项目概览FitMall 是一个面向运动健身人群的全栈 Web 应用承载了电商交易、课程学习、社区互动、训练管理、AI 智能助手五大业务线。项目采用前后端分离架构通过 Docker Compose 一键部署。核心数据流浏览器 → Nginx (80) → Vue 3 SPA → /api/* → FastAPI (8000) → MySQL / Redis / ES / RabbitMQ → Dify AI (云端)2.技术栈一览后端组件技术说明Web 框架FastAPI 0.138 Uvicorn全异步支持 SSE 流式响应数据库MySQL 8.0 SQLAlchemy 2.0异步引擎 aiomysql 驱动缓存 / 会话Redis 7会话存储、验证码、限流、分布式锁搜索引擎Elasticsearch 8.12 IK 分词器商品/课程/帖子/用户四个索引消息队列RabbitMQ 3.13ES 异步同步、订单超时、训练任务认证JWT HTTP-Only Cookie双通道鉴权Redis Session 存储支付支付宝沙箱RSA2-SHA256自签名实现不依赖官方 SDK存储阿里云 OSS带重试和预签名 URL 降级短信阿里云 DypnsapiRedis 存验证码5 分钟过期配置管理Pydantic Settings40 环境变量dev / prod 分离ID 生成自研 Snowflake41 位毫秒时间戳 10 位机器 12 位序列2.1 前端组件技术说明框架Vue 3.5 Composition API TypeScriptscript setup语法构建Vite 8秒级热更新状态管理Pinia 3user / admin / cart 三个 Store路由Vue Router 4嵌套路由 权限守卫样式TailwindCSS 3自定义 “Iron Chalk” 设计系统HTTPAxios 拦截器Cookie 自动携带 并发刷新拦截图表Chart.js体重趋势 / 训练统计WebSocket原生 WebSocket 自封装 Composable实时聊天 在线状态2.2 基础设施组件技术说明容器化Docker Compose6 个服务一键编排Web 服务器Nginx静态文件 API 反向代理内网穿透cpolar支付宝回调 / 开发调试镜像加速阿里云镜像apt / pip / npm 三端加速3.架构设计3.1 领域驱动模块划分后端采用按业务域垂直拆分的模块化结构每个模块内部遵循统一的四层范式module/ ├── models.py # SQLAlchemy 数据模型与数据库表一一对应 ├── schemas.py # Pydantic 请求/响应 SchemaAPI 契约 ├── router.py # FastAPI 路由定义薄层纯路由注册 └── service.py # 业务逻辑核心所有复杂逻辑在这里全局共12 个业务域auth goods course training community cart order ai admin user shared middleware每个域独立演进通过shared/层的公共组件数据库会话、Redis 客户端、ES 客户端、统一响应格式进行横向连接。3.2 请求生命周期HTTP 请求 → CORS 中间件跨域白名单校验 → Request-ID 中间件注入 UUID 追踪链路 → 日志中间件记录 method/path/status/duration → 路由匹配 → 依赖注入DB Session / Redis / Auth User → Service 层业务逻辑 外部调用 → 统一响应格式封装 → {code: 1, data: {...}, message: success} → 异常处理器兜底6 种自定义异常 → HTTP 状态码映射4.那些有意思的技术细节4.1 HTTP-Only Cookie 会话认证用 Redis 替代 JWT这是整个项目最具辨识度的架构决策。传统 JWT 方案的痛点Token 存在localStorage中任何注入的 XSS 脚本都能轻松窃取。一旦 Token 泄露在过期前无法主动撤销。FitMall 的方案登录 → 生成 Snowflake Session Token → 将用户信息存入 Rediskey: session:{token}, TTL: 24h → 将 Token 写入 HTTP-Only Cookie前端 JS 不可读 → 浏览器每次请求自动携带 Cookie → 后端解析 Cookie → Redis 查找 → 注入当前用户到请求上下文为什么比 JWT 更安全防 XSSHTTP-Only Cookie 对 JavaScript 完全不可见即使页面注入恶意脚本也无法窃取 Token即时失效删除 Redis 中的 Session Key 即可让任意 Token 立即失效无需等到过期用户/管理端隔离两套完全独立的 Cookie 名fitmall_sessionvsfitmall_admin_session和 Redis Key 前缀杜绝越权自动续期每次活跃请求自动刷新 Redis TTL只有真正离线的用户才会过期同时保留了 JWT 作为 WebSocket 的鉴权通道浏览器 WebSocket API 无法自定义 Cookie Header实现双通道鉴权。# dependencies.py — 双通道鉴权的核心实现asyncdefget_current_user(request:Request,db:AsyncSessionDepends(get_db),)-dict:# 通道 1Cookie Session主通道tokenrequest.cookies.get(settings.SESSION_COOKIE_NAME)iftoken:user_dataawaitredis_client.get(fsession:{token})ifuser_data:awaitredis_client.expire(fsession:{token},settings.SESSION_EXPIRE_HOURS*3600)returnjson.loads(user_data)# 通道 2Authorization BearerWebSocket 等场景auth_headerrequest.headers.get(Authorization)ifauth_headerandauth_header.startswith(Bearer ):returnverify_jwt_token(auth_header[7:])raiseUnauthorizedException(请先登录)4.2 手搓 Snowflake 分布式 ID 生成器不满足于pip install snowflake-id项目从零实现了一个符合 Twitter Snowflake 规范的 ID 生成器。64 位结构┌─┬──────────────────────────┬──────────────┬──────────────┐ │0│ 41-bit 时间戳 (ms) │ 10-bit 机器码 │ 12-bit 序列号 │ └─┴──────────────────────────┴──────────────┴──────────────┘ ↑ ↑ ↑ 保留位 数据中心(5)节点(5) 4096/ms实现亮点自定义纪元2024-01-01而非 Twitter 的2010-11-04使 ID 可用到 2094 年时钟回拨容错最多容忍 5ms 的时钟回拨超时则抛异常线程安全threading.Lock保护序列号递增双重输出generate_id()返回整数存数据库generate_id_str()返回 Hex 字符串用于 URL所有 Session Token、商品 SN 编号、订单号都通过 Snowflake 生成保证全局唯一且趋势递增。4.3 双通道 ES 同步直写 消息队列兜底当管理员创建/修改一个商品时搜索索引如何保持最新方案双通道写入┌─ 通道 1: 直接写入 ES用户立即搜到 CRUD 操作 ──────────┤ └─ 通道 2: 发布 RabbitMQ 消息 → 消费端异步写入 ↑ 兜底直写失败时由消息队列重试为什么不做纯异步如果管理员刚上架一个商品就去前台搜索纯异步方案可能因为消息延迟导致搜不到。直写方案用户立即可见消息队列作为Eventual Consistency的保障层即使 ES 临时不可用消息也会被持久化并在 ES 恢复后重放。消费端采用指数退避重试5s → 10s → 20s → 40s → 60s最多重试 5 次。# es_sync_tasks.py — 消费端重试逻辑retry_count0whileretry_countMAX_RETRIES:try:ifactionindex:awaitindex_document(index_name,str(doc_id),body)elifactiondelete:awaitdelete_document(index_name,str(doc_id))breakexceptExceptionase:retry_count1ifretry_countMAX_RETRIES:logger.error(ES 同步最终失败)breakdelaymin(INITIAL_RETRY_DELAY*(2**(retry_count-1)),MAX_RETRY_DELAY)awaitasyncio.sleep(delay)4.4 IK 分词器的双分析器策略Elasticsearch 默认分词器对中文很不友好逐字拆分。项目使用了 IK 中文分词器并采用了索引与搜索分析器分离的策略{analysis:{analyzer:{ik_index_analyzer:{tokenizer:ik_max_word},// 索引用细粒度高召回ik_search_analyzer:{tokenizer:ik_smart}// 搜索用粗粒度高精度}}}ik_max_word将文本切分为尽可能多的词条索引阶段用保证增肌蛋白粉能被蛋白粉、“增肌”、“蛋白”、粉等任意组合命中ik_smart做最粗粒度的语义切分搜索阶段用避免苹果手机被拆成苹果手机后匹配到水果效果对比搜索词ik_max_word 搜索ik_smart 搜索“蛋白粉”返回蛋白粉 含有蛋白或粉的商品只返回真正匹配蛋白粉的商品“瑜伽垫”返回瑜伽垫 瑜伽相关商品精确匹配瑜伽垫此外ES 兼容性处理值得一提elasticsearch-py8.19 默认发送compatible-with9头而服务器 ES 8.14 只接受 7 或 8通过 monkey-patch 固定为compatible-with8解决。4.5 AI 三端架构与优雅降级项目集成了 Dify 平台的三个独立 AI 应用应用API 类型降级策略AI 对话助手Chat Streaming (SSE)❌ 无降级正在添加训练计划生成Workflow (Blocking)✅ 模板计划4 种目标类型训练建议Workflow (Blocking)✅ BMI 规则引擎5 级分类SSE 流式对话实现# dify_client.py — 流式消费 Dify SSEasyncforlineinresponse.aiter_lines():ifnotline.startswith(data:):continuedatajson.loads(line[5:].strip())eventdata.get(event,)ifeventmessage:yield{content:data[answer],conversation_id:data[conversation_id]}elifeventerror:raiseDifyClientError(fDify 流式错误:{data[message]})每条消息增量推送给前端SSE 格式前端实时渲染打字效果。优雅降级模式# plan/service.py — 先调 AI失败则用模板try:client_get_dify_client()resultawaitclient.run_workflow(inputs{...})weekly_planresult.get(weekly_plan)exceptDifyClientErrorase:logger.warning(Dify 计划生成失败使用模板计划: %s,e)ifweekly_planisNone:weekly_plan_template_plan(targetdata.target,...)# 本地模板这意味着即使 Dify 宕机或 Token 过期用户依然能得到一份基于目标类型减脂/增肌/塑形/保持的可用训练计划只是缺少 AI 的个性化优化。4.6 Dify Chatflow 工作流从意图识别到商品推荐最新为 AI 助手设计的 Chatflow 工作流实现了意图识别 → 智能搜索 → 格式化推荐的完整链路用户输入想买蛋白粉 → LLM 意图识别 → {category: goods, keyword: 蛋白粉} → HTTP 节点 → GET /api/v1/ai/search?q蛋白粉typegoods → ES 返回 [{id, name, price_text, image, badge, url}, ...] → LLM 格式化 → 推荐文案含 product://123 特殊链接 → 前端渲染 → 可点击的商品卡片关键设计点意图分类用 LLM 而非关键词匹配高容错能理解最近跑步膝盖疼有什么护具推荐吗 goods “跑步护具”product://协议链接不直接用真实 URL而是用自定义协议让前端拦截并渲染成卡片避免 Dify 输出裸露的链接不好看HTTP 节点直接调公网 APIhttp://xxx.xxx.xxx.xxx/api/v1/ai/searchDify Cloud 可直达服务器4.7 订单超时取消与 Redis 分布式锁用户下单后 30 分钟内未支付系统自动取消并回滚库存。实现方式# 1. 下单时投递延迟消息publish_message(ORDER_TIMEOUT_QUEUE,{order_id:order.id,created_at:now.isoformat()})# 2. 消费端计算剩余时间sleep 后检查remaining30*60-elapsed_secondsifremaining0:time.sleep(remaining)# 3. Redis 分布式锁防止多实例重复处理lock_keyforder:timeout:lock:{order_id}acquiredredis_client.set(lock_key,1,nxTrue,ex120)# SET NX EXifnotacquired:return# 其他实例已在处理# 4. 检查订单状态 回滚库存 关闭订单为什么用time.sleep而不用 RabbitMQ TTL 死信队列简单直接一条消息进入队列消费者收到后自己算时间睡觉。避免了死信队列的复杂配置也避免了秒级 TTL 不准的问题RabbitMQ 的 TTL 到秒级才有保证。不过缺点也很明显sleep 期间消费者线程被占用。小规模场景单实例、单线程消费没问题大规模需要换方案。4.8 运行时数据库迁移不用 Alembic 生成迁移脚本而是在应用启动时直接跑增量 SQL# database.pyasyncdef_run_migrations(connection):migrations[ALTER TABLE users ADD COLUMN IF NOT EXISTS height INT DEFAULT NULL,ALTER TABLE spu ADD COLUMN IF NOT EXISTS original_price INT DEFAULT NULL,# ...]forsqlinmigrations:try:awaitconnection.execute(text(sql))exceptException:pass# 幂等列已存在则跳过适用场景小型团队快速迭代避免了编写、review、执行 Alembic 迁移的繁琐流程。每行 SQL 都是幂等的IF NOT EXISTS/ try-catch多次执行也不会出错。不适用场景大型团队需要严格 review 每次数据库变更或有回滚需求。此时应回归 Alembic 版本管理。4.9 WebSocket 实时聊天与在线状态追踪社区的私信功能基于 WebSocket 实现采用双通道保底WebSocket 通道实时双向通信在线状态推送HTTP 降级通道当 WebSocket 连接失败时自动 fallback 到 HTTP POST 发消息在线状态追踪的设计# 在内存中维护当前进程active_connections:dict[int,WebSocket]{}# 在 Redis 中维护跨进程 / 重启恢复awaitredis_client.sadd(chat:online_users,str(user_id))亮点用户上线时先用 JWTWebSocket 连接时携带的短效 Token鉴权然后将 WebSocket 对象注册到内存字典 Redis 集合。下线或断开时同步清理两端。未读消息计数存储在 Redis 中每次用户连接时推送未读数读到消息后实时更新。5.总结与思考5.1 适合学习的技术点HTTP-Only Cookie Redis Session的认证方案比传统 JWT 更安全值得在生产环境采用自研 Snowflake是一个很好的分布式系统入门实践理解 64 位 ID 的每一位含义ES 双分析器策略是中文搜索的标配方案IK 分词器的选择直接影响搜索体验AI 优雅降级是 AI 集成的最佳实践——AI 是锦上添花不是核心链路5.2 可以改进的地方订单超时的time.sleep方案在大流量下会成为瓶颈后期应改用 RabbitMQ 死信队列运行时迁移适合当前阶段但随着团队扩大应切换回 Alembic 版本管理ES 双通道同步存在极小概率的不一致关键场景如库存扣减应优先查 MySQLAI Chat 目前无降级Dify 不可用时会直接报错应添加兜底回复5.3 项目数据后端~8000 行 Python12 个业务模块前端~40 个 Vue 组件3 个 Pinia Store基础设施6 个 Docker 容器4 个 ES 索引外部集成Dify AI、支付宝、阿里云 OSS、阿里云短信、Elasticsearch、RabbitMQ、Redis5.4 后期优化基础设施升级方向Redis-分片集群、分布式锁、缓存、MySQL-主从读写分离、分库分表、MGR 多主、Elasticsearch-分片 副本自动分布式、RabbitMQ-镜像队列集群。6. 项目演示(由于图片没有找所以看起来会奇怪一些目前只是demo阶段)C端B端其他页面就不展示了随便展示了一些项目持续迭代中代码开源维护。如有问题或建议欢迎通过 Issue 或 PR 交流。

相关新闻

接入大模型不等于AI落地

接入大模型不等于AI落地

企业搞AI的方向,从第一步就错了越来越多的企业开始搞AI,但大多数企业花了几个月甚至更长时间,最后发现——AI应用落地了一堆,真正好用的工作流一个都没跑通。问题出在哪里?企业搞AI的方向从第一步就错了——把接入大模…

2026/7/8 3:35:50 阅读更多 →
Harness体系下: Api接口验收测试

Harness体系下: Api接口验收测试

# 用 AI 做接口验收:从 Swagger 到批量报告,10 步标准化流程 > **导读**:开发提测后,接口验收往往卡在「拼参数、写用例、跑请求、写报告」四件事上。本文介绍一套基于 Cursor Agent 的 API 层验收方案——自动拉取 Swagger 元数据、多维生成用例、批量执行断言、输出 …

2026/7/8 3:35:50 阅读更多 →
计算机毕业设计之教案管理系统的设计与实现

计算机毕业设计之教案管理系统的设计与实现

随着世界经济信息化、全球化的到来和互联网的飞速发展,推动了各行业的改革。若想达到安全,快捷的目的,就需要拥有信息化的组织和管理模式,建立一套合理、动态的、交互友好的、高效的教案管理系统。当前的信息管理存在工作效率低&a…

2026/7/8 3:35:50 阅读更多 →

最新新闻

【大模型应用】Harness Engineering

【大模型应用】Harness Engineering

Harness Engineering 一、三代工程概念递进关系(Prompt / Context / Harness)三者是研究范围逐层向外扩张、管控粒度持续放大的递进关系:Prompt Engineering 提示词工程 只研究单次输入话术,优化指令措辞,让模型看懂单…

2026/7/8 4:36:26 阅读更多 →
CSAPP Bomblab实战指南:x86-64汇编逆向与动态调试全解析

CSAPP Bomblab实战指南:x86-64汇编逆向与动态调试全解析

1. 项目概述:这不是一场考试,而是一次逆向工程的沉浸式实战如果你刚打开《深入理解计算机系统》(CSAPP)第3版的第3章,看到“Bomblab”这个名字,第一反应可能是:“这又是个什么抽象概念&#xff…

2026/7/8 4:32:25 阅读更多 →
Loop Engineering:AI智能体的自循环设计

Loop Engineering:AI智能体的自循环设计

Loop Engineering:构建自主循环的AI智能体系统 随着大语言模型能力的提升,AI应用开发正经历一场深刻的范式迁移。从早期专注于单次交互的Prompt Engineering,演进到如今面向复杂、长周期任务的Loop Engineering。这标志着AI开发的核心从“如…

2026/7/8 4:30:24 阅读更多 →
微尺度运动图谱:非牛顿流体中突破扇贝定理的工程实践

微尺度运动图谱:非牛顿流体中突破扇贝定理的工程实践

1. 这不是教科书里的流体力学,而是微尺度世界的“游泳法则”实战笔记你有没有想过,一个比头发丝还细十倍的微型机器人,怎么在血液、黏液或者工业凝胶里游动?它没法像鱼那样甩尾巴,也没法像螺旋藻那样打转——在那种尺度…

2026/7/8 4:28:24 阅读更多 →
卡特加特AI营销超算一体机的应用场景?

卡特加特AI营销超算一体机的应用场景?

在全面了解了卡特加特AI营销超算一体机在各行业的具体应用之后,我们有必要回到一个更根本的问题:为什么这些看似各不相同行业的企业,最终都选择了同一套产品体系?答案在于,卡特加特所提供的不仅是一个解决某个具体营销…

2026/7/8 4:22:23 阅读更多 →
Ubuntu 22.04 安装超好用中文输入法rime-ice(雾凇拼音)过程记录

Ubuntu 22.04 安装超好用中文输入法rime-ice(雾凇拼音)过程记录

Ubuntu 22.04 安装超好用中文输入法rime-ice(雾凇拼音)过程记录 这篇记录一下我在 Ubuntu 22.04 上安装并配置 Fcitx5 Rime 雾凇拼音 的过程。中间踩了一些坑,尤其是 Ubuntu 22.04 的 librime 版本较旧,不能直接使用最新版雾凇拼音,所以这里…

2026/7/8 4:20:22 阅读更多 →

日新闻

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: …

2026/7/8 0:00:48 阅读更多 →
MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N1 到批处理的全路径 一、从"功能正确"到"性能可接受"——MyBatis 批量操作的三段式进化 MyBatis 在日常增删改查场景中几乎是无感的——实体映射直观、SQL 控制灵活。但当数据量从千级上升到十万级、百万级,许…

2026/7/8 0:00:48 阅读更多 →
工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

1. 工业负载控制方案概述在工业自动化、电机驱动和照明控制等高需求场景中,可靠地控制电感和电阻负载是核心挑战之一。TPD2015FN作为东芝的8通道高端智能功率开关IC,配合PIC18F45K22微控制器,能够构建一套稳定、高效的负载控制系统。这套组合…

2026/7/8 0:02:48 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/7 14:24:45 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/7 12:34:47 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/7 15:59:06 阅读更多 →

月新闻