📦项目简介
一套完整应用市场系统:
- 后端:Golang Gin,提供 REST API;
- 移动端:Flutter App(应用详情、下载、评论);
- Web 管理后台:单页面 HTML,管理应用版本、审核、标签、用户。
🚨 踩过的技术问题汇总
1)前端 Web 浏览器 302 下载重大坑
- 现象:后端返回
302 Found+Location重定向到 apk 静态文件;web 使用fetch(redirect:"manual"),浏览器安全限制,JS 拿不到Location响应头,下载失效。 - 误区:单纯修改 CORS
ExposeHeaders:["Location"]浏览器 fetch‑opaqueredirect 下完全无效。 - 最终解决方案:后端废弃 302 重定向;下载接口返回 JSON,返回 apk 静态资源路径
apk_url;前端拿到地址直接访问 static 静态资源触发下载。 - 额外注意:下载接口保留下载计数统计逻辑,不能丢业务统计。
2)Gin 静态路由 404 问题(web 管理页面)
- 现象:单页面 index.html 托管,css/js 报 404;根源:
r.StaticFile("/","web/index.html")只返回 html,不会托管同目录 js/css 静态文件。 - 错误做法:直接
r.Static("/","./web")会覆盖全部 /api/v1 路由,API 全部 404。 - 正确配置:
r.Static("/web", "./web") r.GET("/", func(c *gin.Context){c.File("web/index.html")}) - web 页面内资源引用改为绝对路径
/web/style.css/web/main.js。
3)跨域 CORS 问题
- 浏览器跨域读取特殊响应头,需要配置
Access‑Control‑Expose‑Headers; - OPTIONS 预检请求处理,直接返回 204;
- 注意:302 场景该配置对 fetch 的 opaque 响应无效,所以最终放弃 302 方案。
4)Flutter 下载逻辑改造
- 旧逻辑:Dio 关闭自动重定向
followRedirects:false,读取 302 Location 地址; - 改造:
AppApi.getDownloadRealUrl()请求下载接口拿到 json 中的apk_url静态路径;再用 Dio 直接下载/static/apk/xxx.apk; - 封装工具类
DioDownloadUtil,封装下载状态、进度、本地文件管理; - UI 层只调用工具类,业务下沉 API 和 util,页面
app_detail_page.dart改动最小。
5)页面 UI 布局 bug
- Flutter 详情页面固定高度
SizedBox(height:60)造成 BottomOverflow 溢出;修复:删除固定高度,crossAxisAlignment: CrossAxisAlignment.start顶部对齐。 - Web 单页面:原始逻辑不要随意拆分 html/css/js,拆分容易破坏原有 DOM、交互逻辑,优先最小改动修复 bug。
6)路由与接口路径不匹配
- web 管理后台登录接口后端路由是
/admin/api/login,前端写死/api/v1/admin/login,接口 404; - 后端分组路由要核对,区分普通用户
/api/v1和管理员/admin/api两套分组。
7)鉴权相关
- JWT 鉴权统一放在 Header
Authorization: Bearer token; - 内网临时测试方案不要把 token 放到 URL query 参数:安全风险,token 留在日志、浏览器历史,禁止公网使用。
🧩核心业务设计
1、后端 Golang Gin
- 分层:Handler → Service → Repository;util 封装通用返回
util.Success/util.Fail统一 JSON 格式。 - JWT 中间件
LoginAuth,从 Header 解析 token 获取登录身份信息,写入 gin 上下文actor_id/role/username。 - 下载业务:
GET /api/v1/download/:versionId鉴权、版本校验;调用RecordDownload记录下载行为统计;返回{"code":0,"data":{"apk_url":"/static/apk/xxx.apk"}};- 静态资源路由:
/static提供 apk、图标文件访问。
- 业务模块:
- 应用模块:列表、详情、版本上传更新;
- 审核模块:应用版本待审核队列,通过 / 拒绝;
- 标签模块:标签 CRUD、标签审核;
- 用户模块:注册登录,角色区分普通用户 /admin 管理员;
- 评论模块:一级评论、楼中楼递归回复;
- 申诉模块:用户上传权限申诉。
2、Flutter App 端
- 页面:应用详情页为核心,展示基础信息、多版本、树状嵌套评论、下载按钮。
- 下载状态管理:
DownloadTaskEntity实体,管理 id、保存文件名、状态(idle/downloading/paused/completed/failed)、已下载字节 / 总字节。 - API 层
AppApi统一封装网络请求;Dio 做拦截器自动附加 JWT token。 - UI 特点:评论局部刷新,提交评论不整页 rebuild;递归渲染多层楼中楼回复;下载按钮根据状态切换文字与图标。
3、Web 管理后台(单 HTML)
- 功能:市场浏览、用户管理、应用全量管理、版本审核、标签管理、申诉审批、上传 APK。
- 鉴权:localStorage 存储 token;未登录弹出登录弹窗;区分普通用户 / 管理员权限,部分菜单管理员才可见。
- 下载逻辑:fetch 调用下载接口拿到 apk_url,
window.location.href=apk_url触发浏览器下载。
✨关键设计决策总结
- ❌废弃 302 重定向下载方案,✅采用「接口返回静态 apk 路径」方案,Web 浏览器、Flutter 两端统一适配,规避浏览器 fetch 安全限制。
- Gin 静态资源与 SPA 页面分开托管,不污染 API 路由。
- 下载统计逻辑放在后端下载接口,无论 App/Web 访问,下载计数统一记录。
- Flutter 业务逻辑下沉 API+Util,UI 页面只负责展示,减少页面层改动。
- Web 端尽量保持原始单文件,最小侵入式修改 BUG,避免拆分 HTML/CSS/JS 引入大量回归 bug。

1447

被折叠的 条评论
为什么被折叠?



