《在线画稿交易平台》答辩问答预演

tyrone的头像 发布于 4 天前 10 次阅读 预计阅读时间: 21 分钟 最后更新于 4 天前


按问题类别组织,每题给出参考答案 + 可能追问
加 ⭐ 的是高频必问题,加 ⚠️ 的是论文里有坑的题。


第一类:技术选型类(必问)

⭐ Q1:为什么选 Django?

:Django 是"全家桶"框架,自带 ORM、Admin 后台、用户认证、表单处理这些东西,不用重复造轮子,开发效率高。Flask 太轻量,订单、用户、画稿这些模块自己搭脚手架太费时间。Spring Boot 性能好但学习曲线陡,Python 生态对接支付宝 SDK 也更方便。对一个毕业设计来说,Django 在开发效率和稳定性上是平衡得最好的。


⭐ Q2:为什么用 Vue 而不是 React?

:Vue 中文文档完善、模板语法接近 HTML,对单人开发友好。Ant Design Vue 组件库可以直接拿来用,不用从零写 UI。React 也可以,但 Vue 的双向绑定和单文件组件让我能更快出原型。


Q3:为什么选 MySQL 不用 MongoDB?

:画稿交易场景里有很强的关联关系——用户、订单、画稿、设计师之间是结构化数据,订单还涉及金额,需要 ACID 保证一致性。MongoDB 适合非结构化或高并发写入的日志类数据,这个场景不合适。


⭐ Q4:JWT 和 Session 的区别,为什么选 JWT?

  • Session 是有状态的:服务器存 session 数据,客户端只存 sessionID。多服务器要做共享。
  • JWT 是无状态的:所有信息都在 token 里,服务器只验签名。

选 JWT 是因为前后端分离架构下,无状态更利于水平扩展,跨域更友好。


第二类:安全相关(高频)

⭐ Q5:JWT 被盗用怎么办?

:几个层面防护:

  1. HTTPS 传输:防止中间人抓包
  2. 设置较短过期时间(比如 2 小时),配合 refresh token 续签
  3. 签名密钥保密:放环境变量,不进代码库
  4. 敏感操作(提现等)加二次校验

论文目前是基础实现,生产环境会加 refresh token 机制。


Q6:密码怎么存的?为什么不存明文?

:用 Django 的 make_password 加密存储,底层是 PBKDF2-SHA256 + 盐哈希。登录时用 check_password 校验。

明文存储一旦数据库泄露用户密码全暴露,且很多用户多平台同密码,风险更大。


Q7:怎么防 SQL 注入?

:用 Django ORM,所有查询参数化,框架层面已经防住了。如果用原生 SQL 必须参数化查询,不能字符串拼接。


Q8:怎么防 XSS?

  • 前端 Vue 默认对 {{ }} 插值做 HTML 转义
  • 后端 Django 模板默认转义
  • 用户输入的画稿描述如果允许富文本,需要白名单过滤标签

Q9:怎么防 CSRF?

:JWT 方案下 token 放在请求 Header(不是 Cookie),天然不受 CSRF 攻击影响——CSRF 利用的是浏览器自动带 Cookie 的特性。


⭐ Q10:交易系统怎么保障安全?

:从四个层面来保障:

第一层:身份安全

  • JWT 鉴权
  • 密码加密存储
  • 设计师人工审核
  • 角色权限隔离

第二层:传输安全

  • HTTPS 加密
  • 支付宝接口 RSA 签名验签
  • CORS 配置只允许指定域名

第三层:资金安全(最关键)

  • 支付宝官方接口处理资金
  • 支付回调用支付宝公钥验签
  • 订单号做幂等控制
  • 余额扣减用数据库事务
  • 退款权限只给管理员
  • 金额服务端重新计算,不信前端

第四层:行为安全

  • ORM 防 SQL 注入
  • 转义防 XSS
  • JWT 放 Header 免疫 CSRF
  • 敏感接口限流
  • 操作日志审计

⭐ Q11:加密方法有哪些?

:项目里加密分三类:

1. 密码存储 —— 哈希加盐(不是真正的加密)

  • 算法:PBKDF2 + SHA256
  • 过程:随机盐 + 密码 → 哈希 39 万轮 → 入库
  • 存储格式:pbkdf2_sha256$迭代次数$盐$哈希值
  • 校验:登录时取出盐做同样运算,比对哈希值

2. 传输加密 —— HTTPS(TLS)

  • 浏览器到服务器全链路加密
  • 防中间人窃听

3. 支付宝接口 —— RSA 非对称加密 + 数字签名

  • 平台和支付宝各有一对密钥
  • 平台用平台私钥签名 → 支付宝用平台公钥验签
  • 支付宝用支付宝私钥签名 → 平台用支付宝公钥验签
  • 必须验签,不验签的话攻击者能伪造支付成功通知

JWT 签名 —— HMAC-SHA256

  • 三部分:Header.Payload.Signature
  • 注意:Payload 是 Base64 编码不是加密,不要放敏感信息

Q12:对称加密和非对称加密的区别?

  • 对称加密(AES、DES):加解密同一个密钥,速度快,问题是密钥分发
  • 非对称加密(RSA、ECC):一对密钥,公钥加密私钥解密,速度慢但解决密钥分发
  • 实际系统两者结合:用 RSA 协商出 AES 密钥,后续用 AES 通信(HTTPS 就这么干的)

Q13:哈希、加密、编码的区别?

  • 编码(Base64):可逆,不是加密,只是格式转换
  • 哈希(SHA256):单向不可逆,相同输入得相同输出
  • 加密(AES/RSA):可逆,需要密钥才能解密

Q14:为什么不用 MD5 存密码?

:MD5 已经不安全:

  1. 碰撞攻击:能找到两个不同输入产生相同哈希
  2. 速度太快:现代 GPU 每秒能算几十亿次,暴力破解快
  3. 没有加盐和迭代设计

PBKDF2、bcrypt、scrypt、argon2 故意设计得"慢"来对抗暴力破解。


第三类:业务逻辑类(容易踩坑)

⭐⚠️ Q15:买家余额扣了但卖家加余额失败,钱怎么办?

论文最大的坑,必须诚实回答

:目前 pay 函数是顺序执行的,没有用数据库事务保护,确实存在中间步骤失败导致数据不一致的风险。生产环境应该用 @transaction.atomic 装饰器把扣款、加款、改订单状态包在一个事务里,保证要么全成功要么全回滚。这是后续要优化的点。

@transaction.atomic
def pay(self, order_id):
    user = User.objects.select_for_update().get(id=user_id)
    # ... 扣款、加款、改状态全在事务里

⭐ Q16:高并发下两个人同时买同一张画稿,余额扣了两次怎么办?

:需要加锁:

  • 悲观锁select_for_update() 在事务里锁住用户余额行
  • 乐观锁:余额表加 version 字段,更新时比对

论文当前实现没处理并发,是可优化点。


⭐ Q17:支付宝回调可能被重复通知,会重复加余额吗?

:支付宝异步通知确实可能重复发。防重的做法:

  1. 通过 out_trade_no 查订单
  2. 判断订单状态:已经是 PAID 的直接返回 success,不再加余额

论文里 async_notify 没有明确这步幂等判断,是可以补充的。


Q18:支付宝回调是怎么验签的?防伪造?

:支付宝 SDK 自带 verify 方法,用支付宝公钥对回调参数做 RSA 验签。只有支付宝私钥签的才能通过验签,攻击者伪造不了。


Q19:怎么防止用户改前端的价格直接低价买?

服务端永远以数据库里的画稿价格为准。下单接口只接收 draft_id,价格从数据库查出来计算,前端传的金额只用来显示,不参与扣款逻辑。


Q20:画稿被买之后还能被别人买吗?

:当前设计是可重复售卖——is_outline 字段控制是否在售。如果要做版权独占需要购买后自动下架。这是产品定义层面的选择。


Q21:退款时如果设计师已经把余额提现走了怎么办?

:当前 return_order 函数会检查 designer.balance < draft.price,余额不够就抛异常退款失败。

生产上应该有"冻结期"——画稿售出后金额先冻结 N 天再可提现,防止退款时无款可退。


第四类:架构 & 设计类

⭐ Q22:为什么前后端分离?

  1. 职责清晰,前端专注 UI,后端专注业务
  2. 后端只提供 REST API,可同时支持 Web、小程序、App
  3. 前后端独立部署、独立迭代
  4. 前端可以走 CDN 加速

⭐⚠️ Q23:user 表和 designer 表字段几乎一样,为什么分两张?

论文设计上的明显问题,诚实回答

:当时考虑设计师有专属属性(认证状态、作品集等)想做扩展,但目前两张表字段确实高度重复,造成数据冗余

更合理的做法有两种:

  1. 单 user 表 + role 字段("user"/"designer"/"admin")
  2. user 主表 + designer_profile 副表,副表只存设计师独有字段

这是后续要重构的地方。


Q24:系统架构是几层?

:四层

  1. 用户层:浏览器 + Vue 前端
  2. Web 应用服务层:Django,分视图层、业务层、数据访问层
  3. 数据库层:MySQL
  4. 操作系统层:Linux/Windows

Q25:REST API 设计遵循什么规范?

:用 HTTP 动词表达操作(GET/POST/PUT/DELETE),URL 用名词复数,状态码用 HTTP 标准(200/400/401/500)。响应统一格式 {code, msg, data}


第五类:数据库字段类

⭐ Q26:为什么用户 ID 用 bigint?

:三方面考虑:

1. 容量足够 + 扩展性

  • int 4 字节,最大 21 亿;bigint 8 字节,最大 9.2×10¹⁸
  • 互联网项目用 bigint 是行业惯例
  • 避免后期数据量大了改类型,迁移成本高

2. 性能影响有限

  • 现代 CPU 是 64 位,处理 bigint 和 int 速度几乎一样
  • 多 4 字节相比 varchar 主键还是快得多

3. 自增主键的优势

  • 空间小(8 字节 vs UUID 36 字节)
  • InnoDB 友好,自增主键插入永远在 B+ 树末尾,不会页分裂
  • 索引效率高,整数比较快

关于 (20):很多人误以为是位数,其实只是显示宽度,配合 ZEROFILL 才有意义。MySQL 8.0.17 之后这个括号已经废弃。


⭐⚠️ Q27:为什么余额、价格、金额用 float?金额不会丢精度吗?

论文最显眼的坑

:float 是浮点数,存储金额会有精度问题,比如 0.1 + 0.2 在 float 下不等于 0.3。涉及钱的场景,正确做法是 DECIMAL(10,2)——总共 10 位数字,2 位是小数,最大能存 99999999.99,对画稿交易场景够用。也可以用 bigint 存"分"。

当时没意识到这个问题,是数据库设计上的疏漏,生产环境必须改成 DECIMAL。


Q28:手机号为什么用 varchar 不用 bigint?

  1. 手机号不参与运算,存数字类型没意义
  2. 可能有前导 0 或国际区号 "+86",bigint 存不了
  3. varchar 方便做格式校验和模糊查询

Q29:状态字段(status)为什么用 varchar 不用 int?

:用字符串是为了可读性——直接看数据就知道是 "pending" 还是 "completed",不用查枚举映射表。

缺点是占空间、可能拼错。更优做法是用 tinyint + 应用层枚举,性能和可读性兼顾。


⚠️ Q30:orders 表既有 status 又有 is_cancel,是不是冗余?

:您说得对,这两个字段语义重叠。保留 is_cancel 可能是为了快速过滤未取消的订单(避免字符串比较),但加索引到 status 也能解决。如果重做我会去掉 is_cancel,只保留 status。


Q31:为什么不用 UUID 做主键?

:UUID 优点是分布式场景下不用协调就能生成唯一 ID,但缺点:

  1. 占空间大:36 字符 vs 8 字节
  2. 无序性破坏 B+ 树:UUID 插入位置随机,频繁页分裂,写入性能差
  3. 可读性差
  4. 索引效率低:字符串比较慢

折中方案是雪花算法(Snowflake)——bigint 类型 + 趋势递增 + 分布式唯一。


Q32:为什么字符集用 utf8mb4 不是 utf8?

:MySQL 的 utf8 是个历史坑——只支持 3 字节字符,存不了 4 字节字符(emoji、生僻字)。utf8mb4 才是真正的 UTF-8。画稿描述、用户昵称都可能有 emoji,必须用 utf8mb4。


Q33:为什么用 InnoDB 不用 MyISAM?

  1. InnoDB 支持事务,MyISAM 不支持
  2. InnoDB 支持外键,MyISAM 不支持
  3. InnoDB 行锁,MyISAM 表锁,并发性能 InnoDB 好
  4. MySQL 5.5 之后 InnoDB 已经是默认引擎

Q34:哪些字段加了索引?

  • user.username:登录时按用户名查
  • orders.user_id:查"我的订单"
  • draft.user_id:查设计师的画稿列表

原则:高频查询条件 + 区分度高的字段加索引,写多读少不加(索引拖慢写入)。


第六类:性能 & 扩展性

Q35:访问量大了怎么办?

  1. 数据库:读写分离、Redis 缓存热门画稿
  2. 静态资源:图片 OSS + CDN
  3. 应用层:Django 多实例 + Nginx 负载均衡
  4. 接口:分页、字段裁剪

Q36:图片存哪里?大量图片怎么处理?

:当前 image_url 是字符串路径,文件存服务器本地 media 目录。

生产应该用对象存储(OSS / 七牛),CDN 加速,本地只存 URL。还可以做缩略图自动生成。


Q37:搜索画稿用 LIKE 查询吗?大数据量下慢怎么办?

:当前是 MySQL LIKE 模糊查询,数据量小没问题。数据量大要换 ElasticSearch 做全文检索,支持分词、相关度排序、高亮。


第七类:测试相关

Q38:测试覆盖率多少?做了哪些测试?

:论文里主要是功能测试,覆盖了注册、登录、设计师认证、充值、画稿交易等核心流程。还提到性能测试方法(JMeter / Locust)和安全测试方法(SQL 注入、XSS、CSRF),但实际数据没在论文里展开。


Q39:怎么测的支付宝接口?真的付了钱吗?

:用支付宝沙箱环境——支付宝开放平台提供的测试账号和测试金额,所有调用都是模拟的,不涉及真实资金。


第八类:灵魂拷问类

⭐ Q40:你这个项目和淘宝、Etsy 比有什么优势?

:不是要替代它们,而是垂直化——专注画稿交易场景:

  1. 设计师认证机制专门针对画稿创作者
  2. 交易流程围绕"数字作品授权"设计
  3. 后期可以做版权保护、AI 推荐这些垂直能力

⭐ Q41:项目最难的部分是什么?

:支付宝接口对接最难,因为:

  1. 异步回调机制要理解
  2. 验签、加密、回调地址配置容易出错
  3. 沙箱环境配置坑多

⭐ Q42:如果让你重做一遍,会怎么改?

  1. user 和 designer 合表 + role 字段
  2. 金额用 DECIMAL
  3. 交易加事务和并发控制
  4. 加 Redis 缓存
  5. 引入消息队列处理异步任务(订单超时自动取消)
  6. 加评论、评分、推荐算法

⭐ Q43:项目有哪些问题或漏洞?

(主动暴露 2 个加分):

从设计、安全、性能三个角度都有可优化空间:

设计上

  • 金额用 float 应改 DECIMAL
  • user 和 designer 表字段冗余
  • orders.is_cancel 与 status 重复

安全上

  • 交易没加数据库事务
  • 支付回调缺少幂等检查
  • 没有并发控制

性能上

  • 没有 Redis 缓存
  • 图片存本地
  • 搜索用 LIKE

这些都是可以优化的点,体现了对项目的反思。


Q44:项目独立完成吗?借鉴了什么?

:参考了开源 Django 电商项目的订单状态机设计、支付宝官方文档的接入流程,UI 用了 Ant Design Vue 现成组件。但业务逻辑、数据库设计、整体架构是独立完成的


答辩策略

核心原则

  1. 承认问题 + 给改进方案 > 硬撑
  • 老师反感的是不懂装懂,不是不完美
  1. 主动暴露 1-2 个问题
  • 推荐:金额用 float、交易没加事务
  • 显得有反思能力,加分项
  1. 不要把答辩稿背得太死
  • 老师一打断就慌
  • 理解项目结构 > 背稿子
  1. 多说"我考虑过 A 和 B 两种方案"
  • 体现思考过程
  • 比直接给答案更显严谨
  1. 不要主动暴露的雷区
  • 私钥硬编码(不专业)
  • 测试覆盖不足(打脸论文测试章节)
  • 这些被问到再答

Top 10 必答题清单

把这 10 题答案背熟,覆盖答辩 80% 问题:

排名问题关键词
1为什么选 Django/Vue/MySQL全家桶、易用、ACID
2JWT vs Session无状态、水平扩展
3密码怎么存PBKDF2-SHA256 + 盐
4交易系统怎么保障安全身份/传输/资金/行为四层
5加密方法哈希/HTTPS/RSA 三类
6余额扣了卖家加失败怎么办数据库事务(坑)
7支付回调重复怎么办幂等性 + 订单号
8user 和 designer 为什么分两张表承认冗余(坑)
9金额为什么用 float承认错误,应改 DECIMAL(坑)
10bigint 用户 ID 为什么容量+性能+扩展性

紧急救场话术

完全不会答的问题

"这个问题我之前没有深入考虑过,您说的方向我会下来重点研究/优化。我目前的实现是 XX,可能存在 YY 的不足。"

被指出 bug

"感谢老师指出,这确实是我没考虑到的点。正确的做法应该是 XX。我会在后续版本中补上这块。"

追问技术细节超出能力

"这部分我用到的程度是 XX,更深层的原理我还在学习中。能请您指点一下吗?"

把姿态放低,承认不足,比硬编错答案安全得多

此作者没有提供个人介绍。
最后更新于 2026-05-06