20.1 前后端分离架构
20.1 前后端分离架构
现代电商平台普遍采用前后端分离架构,这种架构模式带来了开发效率、可扩展性和团队协作上的显著优势。本节将深入讲解如何设计和实现一个高效的前后端分离电商系统。
架构设计原则
1. 分层架构示意图
┌───────────────────────────────────────────────────────────────┐
│ 客户端应用 (Client) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ UI组件 │ ←→ │ 状态管理 │ ←→ │ API服务层 │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
└───────────────────────────────────────────────────┬──────────┘
↓
┌───────────────────────────────────────────────────┬──────────┐
│ API网关层 (Gateway) │ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 路由分发 │ ←→ │ 认证鉴权 │ ←→ │ 请求转发 │ ←─┐ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │ │
└───────────────────────────────────────────────────┬───────┘ │
↓ │
┌───────────────────────────────────────────────────┬──────────┐│
│ 微服务层 (Microservices) │ ││
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││
│ │ 用户服务 │ │ 商品服务 │ │ 订单服务 │ ... ││
│ └─────────────┘ └─────────────┘ └─────────────┘ ││
└───────────────────────────────────────────────────┬──────────┘│
↓ │
┌───────────────────────────────────────────────────┬──────────┐│
│ 数据层 (Data) │ ││
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││
│ │ MySQL │ │ MongoDB │ │ Redis │ ... ││
│ └─────────────┘ └─────────────┘ └─────────────┘ ││
└───────────────────────────────────────────────────────────────┘
前端架构实现
2. 现代前端项目结构
frontend/
├── public/ # 静态资源
├── src/
│ ├── api/ # API服务层
│ │ ├── auth.js # 认证相关API
│ │ ├── products.js # 商品相关API
│ │ └── ... # 其他API模块
│ ├── assets/ # 静态资源
│ ├── components/ # 公共组件
│ ├── composables/ # Vue组合式函数
│ ├── layouts/ # 页面布局
│ ├── router/ # 路由配置
│ ├── stores/ # 状态管理
│ ├── styles/ # 全局样式
│ ├── utils/ # 工具函数
│ └── views/ # 页面组件
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
└── vue.config.js # 构建配置
3. API服务层封装
// src/api/base.js
import axios from 'axios';
import { useAuthStore } from '@/stores/auth';
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 30000,
withCredentials: true
});
// 请求拦截器
apiClient.interceptors.request.use(config => {
const authStore = useAuthStore();
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`;
}
return config;
});
// 响应拦截器
apiClient.interceptors.response.use(
response => response.data,
async error => {
const originalRequest = error.config;
// 自动刷新token逻辑
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const authStore = useAuthStore();
await authStore.refreshToken();
return apiClient(originalRequest);
} catch (refreshError) {
authStore.logout();
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default apiClient;
4. 商品模块API示例
// src/api/products.js
import apiClient from './base';
export default {
// 获取商品列表
getProducts(params = {}) {
return apiClient.get('/products', { params });
},
// 获取商品详情
getProduct(id) {
return apiClient.get(`/products/${id}`);
},
// 创建商品
createProduct(productData) {
return apiClient.post('/products', productData);
},
// 搜索商品
searchProducts(query) {
return apiClient.get('/products/search', {
params: { q: query }
});
}
};
后端架构实现
5. 微服务网关配置
// gateway/src/app.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const jwtAuth = require('./middlewares/jwtAuth');
const app = express();
// 认证服务直接路由
app.use('/auth', createProxyMiddleware({
target: 'http://auth-service:3001',
changeOrigin: true
}));
// 需要认证的路由
app.use('/api', jwtAuth, createProxyMiddleware({
target: 'http://api-service:3002',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}));
// 商品服务路由
app.use('/products', jwtAuth, createProxyMiddleware({
target: 'http://product-service:3003',
changeOrigin: true
}));
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
module.exports = app;
6. JWT认证中间件
// gateway/src/middlewares/jwtAuth.js
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
// 从Cookie或Authorization头获取token
const token = req.cookies.token ||
req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Unauthorized' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(401).json({ error: 'Invalid token' });
}
};
前后端协作规范
7. API设计规范
RESTful API 最佳实践:
-
资源命名:
- 使用名词复数形式:
/products、/users - 嵌套资源:
/products/{id}/reviews
- 使用名词复数形式:
-
HTTP方法:
- GET:获取资源
- POST:创建资源
- PUT/PATCH:更新资源
- DELETE:删除资源
-
响应格式:
{ "data": { "id": "123", "type": "products", "attributes": { "name": "智能手机", "price": 2999 }, "relationships": { "category": { "data": { "id": "1", "type": "categories" } } } }, "meta": { "total": 100, "page": 1 }, "links": { "self": "/products/123", "related": "/categories/1" } } -
错误处理:
{ "error": { "code": "invalid_parameter", "message": "价格必须是数字", "details": { "field": "price", "value": "abc" } } }
8. 接口版本管理
-
URL路径版本控制:
GET /api/v1/products POST /api/v2/products -
请求头版本控制:
GET /api/products Accept: application/vnd.myapi.v1+json -
语义化版本策略:
- v1.0.0 → 初始稳定版本
- v1.1.0 → 向后兼容的新功能
- v2.0.0 → 不兼容的API变更
部署架构设计
9. 容器化部署方案
# 前端Dockerfile示例
FROM node:16 as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# 后端网关Dockerfile示例
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
10. Nginx配置优化
# nginx.conf
upstream backend {
server gateway:3000;
keepalive 64;
}
server {
listen 80;
server_name example.com;
# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# API代理
location /api {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
}
# WebSocket支持
location /socket.io {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
性能优化策略
11. 前端性能优化
-
代码分割:
// 动态导入组件 const ProductDetail = () => import('@/views/ProductDetail'); -
预加载关键资源:
<link rel="preload" href="/fonts/roboto.woff2" as="font" type="font/woff2" crossorigin> -
API请求优化:
// 使用AbortController取消重复请求 const controller = new AbortController(); fetch('/api/products', { signal: controller.signal }); // 取消请求 controller.abort();
12. 后端性能优化
-
缓存策略:
// Redis缓存中间件 const cache = (req, res, next) => { const key = req.originalUrl; redis.get(key, (err, data) => { if (data) { return res.json(JSON.parse(data)); } next(); }); }; -
数据库查询优化:
// 添加索引后查询 Product.find() .where('price').gt(100).lt(1000) .sort('-createdAt') .select('name price image') .limit(10) .lean(); -
负载均衡配置:
upstream backend { server gateway1:3000; server gateway2:3000; server gateway3:3000; # 最少连接算法 least_conn; # 健康检查 check interval=3000 rise=2 fall=3 timeout=1000; }
安全最佳实践
13. 前端安全措施
-
CSP策略:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: storage.example.com;"> -
XSS防护:
// 自动转义HTML function sanitize(input) { const div = document.createElement('div'); div.textContent = input; return div.innerHTML; } -
敏感操作确认:
// 关键操作需要重新验证密码 async function confirmCriticalAction(password) { const response = await apiClient.post('/confirm-action', { password }); return response.data.confirmed; }
14. 后端安全措施
-
速率限制:
const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15分钟 max: 100, // 每个IP限制100次请求 message: '请求过于频繁,请稍后再试' }); app.use('/api/', limiter); -
SQL注入防护:
// 使用参数化查询 const [products] = await connection.execute( 'SELECT * FROM products WHERE category = ? AND price > ?', [category, minPrice] ); -
请求验证:
const { body } = require('express-validator'); router.post('/products', body('name').isString().trim().notEmpty(), body('price').isFloat({ min: 0 }), body('stock').isInt({ min: 0 }), handleValidationErrors, productController.create );
监控与日志
15. 前端监控
// 错误监控
window.addEventListener('error', (event) => {
fetch('/api/logs', {
method: 'POST',
body: JSON.stringify({
type: 'client_error',
message: event.message,
stack: event.error?.stack,
filename: event.filename,
lineno: event.lineno,
colno: event.colno
})
});
});
// 性能监控
const perfData = window.performance.timing;
const loadTime = perfData.loadEventEnd - perfData.navigationStart;
sendAnalytics('page_load', { duration: loadTime });
16. 后端监控
// 请求日志中间件
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logRequest({
method: req.method,
path: req.path,
status: res.statusCode,
duration,
ip: req.ip,
userAgent: req.get('User-Agent')
});
});
next();
});
// 异常监控
process.on('uncaughtException', (err) => {
logError({
type: 'uncaught_exception',
error: err.stack,
timestamp: new Date()
});
process.exit(1);
});
通过以上架构设计和实现方案,你可以构建一个高性能、可扩展的前后端分离电商平台。接下来我们将深入讲解RESTful API设计的最佳实践。
#前端开发
分享于 2025-03-25
上一篇:19.3 JWT 身份验证
下一篇:20.2 RESTful API 设计