1. 项目概述
去年接手了一个零食电商平台的开发项目,采用Django+Vue的前后端分离架构。这个看似普通的商城系统,在实际开发中遇到了不少值得分享的技术点和踩坑经验。今天就把这个项目的完整实现过程和关键技术细节整理出来,希望能给正在开发类似系统的同行一些参考。
这个零食商城系统主要包含商品展示、购物车、订单管理、支付对接等核心模块。前端采用Vue3+Element Plus实现响应式界面,后端使用Django Rest Framework构建API服务,数据库选用MySQL配合Redis缓存。系统上线后日均PV达到5万+,经受住了618大促的流量考验。
2. 技术选型与架构设计
2.1 为什么选择Django+Vue
选择这个技术栈主要基于以下几点考虑:
- 开发效率:Django自带Admin后台和ORM,能快速搭建业务模型;Vue的组件化开发模式适合电商这类交互复杂的场景
- 性能考量:Django的缓存机制和Vue的虚拟DOM都能有效提升系统响应速度
- 生态完善:两者都有丰富的第三方库支持,比如Django Rest Framework和Vue Router
- 团队适配:团队成员对Python和JavaScript都比较熟悉
2.2 系统架构图
前端层(Vue) ↔ API层(DRF) ↔ 业务层(Django) ↔ 数据层(MySQL+Redis)这种分层架构的关键优势在于:
- 前后端完全解耦,可以独立开发和部署
- API层作为中间件,便于后续扩展微服务
- 数据库读写分离,Redis缓解高并发压力
3. 核心功能实现
3.1 商品模块设计
商品表设计采用了"主表+扩展表"的方案:
class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=10, decimal_places=2) stock = models.IntegerField(default=0) # 其他公共字段... class ProductDetail(models.Model): product = models.OneToOneField(Product, on_delete=models.CASCADE) description = models.TextField() spec = models.JSONField() # 存储规格参数 # 其他扩展字段...这种设计的优点:
- 高频查询字段放在主表提升性能
- 大文本和JSON数据放在扩展表减少主表体积
- 便于实现商品的多规格展示
3.2 购物车实现方案
购物车功能需要考虑的几个关键点:
- 数据结构:使用Redis hash存储用户ID和商品ID的映射关系
- 并发控制:采用乐观锁解决库存冲突
- 失效机制:设置7天自动过期时间
核心代码示例:
def add_to_cart(user_id, product_id, quantity): with transaction.atomic(): product = Product.objects.select_for_update().get(id=product_id) if product.stock < quantity: raise Exception("库存不足") redis_client.hincrby( f"cart:{user_id}", product_id, quantity ) product.stock -= quantity product.save()3.3 订单系统设计
订单模块采用了状态机模式:
class Order(models.Model): STATUS_CHOICES = ( ('unpaid', '待支付'), ('paid', '已支付'), ('shipped', '已发货'), ('completed', '已完成'), ('cancelled', '已取消') ) status = models.CharField(max_length=20, choices=STATUS_CHOICES) # 其他字段... def can_cancel(self): return self.status in ['unpaid', 'paid']状态转换通过信号量触发相关业务逻辑:
@receiver(pre_save, sender=Order) def order_status_change(sender, instance, **kwargs): if instance.id: original = Order.objects.get(id=instance.id) if original.status != instance.status: # 触发状态变更处理逻辑 handle_status_change(original.status, instance.status)4. 性能优化实践
4.1 缓存策略
采用多级缓存方案:
- CDN缓存:静态资源缓存
- 页面缓存:Vue的keep-alive组件
- API缓存:Django的cache_page装饰器
- 数据缓存:Redis缓存热点数据
缓存更新采用"先更新数据库再删除缓存"的策略,避免缓存一致性问题。
4.2 数据库优化
- 索引优化:为高频查询字段添加索引
class Meta: indexes = [ models.Index(fields=['name']), models.Index(fields=['price']), ] - 查询优化:使用select_related和prefetch_related减少查询次数
- 分库分表:用户数据和订单数据分离到不同数据库
4.3 前端性能优化
- 组件懒加载:
const ProductDetail = () => import('./views/ProductDetail.vue') - 图片懒加载:使用Intersection Observer API
- 请求合并:将多个API请求合并为单个请求
- 本地缓存:使用localStorage缓存用户偏好设置
5. 安全防护措施
5.1 常见攻击防护
- XSS防护:
- 前端使用DOMPurify过滤HTML
- 后端设置Django的SECURE_BROWSER_XSS_FILTER=True
- CSRF防护:
- 使用Django内置的CsrfViewMiddleware
- 前端axios配置withCredentials=true
- SQL注入:
- 使用ORM而非原生SQL
- 必要时的原生查询使用参数化查询
5.2 数据安全
- 敏感信息加密:
from django.db import models from django_cryptography.fields import encrypt class User(models.Model): id_card = encrypt(models.CharField(max_length=100)) - 日志脱敏:自定义日志过滤器对手机号、身份证等敏感信息进行脱敏处理
- 权限控制:基于JWT的细粒度权限控制
6. 部署与监控
6.1 生产环境部署
采用Docker+Nginx+Gunicorn方案:
version: '3' services: web: build: . command: gunicorn core.wsgi:application --bind 0.0.0.0:8000 volumes: - static:/app/static depends_on: - redis - db nginx: image: nginx:latest ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - static:/app/static depends_on: - web6.2 监控方案
- 应用监控:Prometheus+Grafana监控接口响应时间和错误率
- 日志收集:ELK收集和分析日志
- 业务监控:自定义埋点监控关键业务流程
7. 踩坑经验分享
7.1 跨域问题解决方案
开发环境下的跨域处理:
CORS_ALLOWED_ORIGINS = [ "http://localhost:8080", "http://127.0.0.1:8080" ]生产环境推荐使用Nginx反向代理解决跨域,避免直接开放CORS。
7.2 支付对接注意事项
- 异步通知处理:一定要验证签名和订单金额
- 幂等设计:支付回调接口需要处理重复通知
- 对账机制:每日定时对账,发现异常订单
7.3 高并发场景下的库存扣减
最初使用简单的UPDATE语句导致超卖:
UPDATE products SET stock = stock - 1 WHERE id = 123优化方案:
- 使用SELECT FOR UPDATE加行锁
- 在Redis中预扣减库存
- 引入消息队列异步处理
8. 项目扩展方向
- 推荐系统:基于用户行为的协同过滤推荐
- 秒杀系统:独立部署的秒杀微服务
- 智能客服:集成NLP技术的在线客服
- 数据分析:用户行为分析和销售预测
这个项目从技术选型到最终上线历时3个月,最大的体会是电商系统看似简单,但要在保证性能和安全的前提下实现良好的用户体验,需要在前端交互、后端架构和运维部署等多个环节做好平衡。特别是在高并发场景下,一个小小的设计缺陷就可能引发严重的系统问题。