共计 3246 个字符,预计需要花费 9 分钟才能阅读完成。
开篇:为什么你的全栈项目总在联调阶段崩溃?
每次启动新项目时,我们总会遇到这些经典场景:
- 前端已经按「口头约定」完成了页面开发,后端却说接口字段需要调整
- 后端返回的数据结构突变,导致前端大量类型报错
- 联调时发现漏了鉴权参数,需要前后端同时修改多处代码
这些问题的本质是 协作模式缺陷。下面这个方案,让我们团队的前后端协作效率提升了 300%。
技术选型:为什么是这些组合?
前端技术栈
- Vue 3 组合式 API:逻辑关注点分离,比 Option API 更适合复杂交互
- Pinia 替代 Vuex:更简单的类型推导,去掉繁琐的 mutations
- TypeScript:不是可选是必选!后面你会看到类型共享的威力
后端技术栈
- Koa/Express:轻量灵活,中间件机制适合 API 服务
- TypeScript:与前端共享类型定义的关键
- Prisma:类型安全的 ORM,自动生成数据库实体类型
协作核心

采用 契约先行开发模式:
- 先用 OpenAPI 规范定义接口
- 自动生成前端请求代码和 Mock 数据
- 前后端基于契约并行开发
实战:从类型共享到请求封装
共享类型定义
创建shared/types.ts:
// 用户相关类型
export interface User {
id: number
username: string
avatar?: string // 可选字段用? 标记
}
// API 响应通用结构
export interface ApiResponse<T> {
code: number
data: T
message?: string
}
增强型 axios 封装
src/utils/request.ts:
import axios, {AxiosRequestConfig} from 'axios'
import {ApiResponse} from '../../shared/types'
// 创建实例时配置默认值
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE,
timeout: 10000
})
// 请求拦截器:注入 token
service.interceptors.request.use(config => {const token = localStorage.getItem('ACCESS_TOKEN')
if (token) {config.headers!['Authorization'] = `Bearer ${token}`
}
return config
})
// 响应拦截器:处理通用逻辑
service.interceptors.response.use(
response => {
// 处理二进制数据
if (response.config.responseType === 'blob') {return response.data}
// 验证接口返回格式
if (!response.data?.hasOwnProperty('code')) {throw new Error('Invalid API response structure')
}
// 业务错误处理
if (response.data.code !== 200) {return Promise.reject(response.data)
}
return response.data.data
},
error => {
// 统一错误提示
if (error.response?.status === 401) {router.push('/login')
}
return Promise.reject(error)
}
)
// 泛型请求方法
export function request<T>(config: AxiosRequestConfig) {return service(config) as Promise<T>
}
契约先行:OpenAPI 工作流
定义规范
api/openapi.yaml:
openapi: 3.0.0
info:
title: 用户服务 API
version: 1.0.0
paths:
/users/{id}:
get:
tags: [User]
parameters:
- $ref: '#/components/parameters/UserId'
responses:
200:
description: 用户详情
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
components:
parameters:
UserId:
name: id
in: path
required: true
schema:
type: integer
schemas:
UserResponse:
type: object
properties:
code:
type: integer
data:
$ref: '#/components/schemas/User'
自动生成工具链
在 package.json 中添加脚本:
{
"scripts": {
"generate:api": "openapi-generator-cli generate -i api/openapi.yaml -o src/api -g typescript-axios",
"mock:server": "prism mock api/openapi.yaml"
}
}
运行后会生成:
- 完整的 TS 类型定义
- 带类型提示的请求方法
- 可运行的 Mock 服务
避坑指南
跨域解决方案
开发环境推荐使用 Vite Proxy:
// vite.config.js
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
})
生产环境务必配置 Nginx:
location /api {
proxy_pass http://backend-service;
proxy_set_header Host $host;
}
JWT 实践要点
- 前端存储:优先使用 httpOnly Cookie
- 刷新机制:
// 在响应拦截器中处理 token 刷新 if (error.response?.data?.code === 40102) { try {const { token} = await refreshToken() localStorage.setItem('ACCESS_TOKEN', token) return service(error.config) } catch {// 跳转登录} } - 安全措施:定期轮换签名密钥
性能优化
前端 Bundle 分析
使用rollup-plugin-visualizer:
// vite.config.js
import visualizer from 'rollup-plugin-visualizer'
export default {
plugins: [
visualizer({
open: true,
filename: 'bundle-analysis.html'
})
]
}
后端监控方案
安装express-status-monitor:
const monitor = require('express-status-monitor')({
title: 'API 监控',
path: '/status',
spans: [{ interval: 1, retention: 60} // 保留最近 1 分钟数据
]
})
app.use(monitor)
思考:如何走向生产级?
当我们完成基础架构搭建后,下一步需要考虑:
- 接口变更时如何保证多端同步更新?
- 如何设计渐进式发布方案?
- 怎样建立性能基准测试体系?
建议从 API 版本控制开始:
paths:
/v1/users:
$ref: './users.v1.yaml'
/v2/users:
$ref: './users.v2.yaml'
这只是一个起点,真正的工程化还需要 CI/CD 流水线、监控告警等配套措施。你在全栈开发中还遇到过哪些棘手问题?欢迎在评论区分享你的实战经验。
正文完
发表至: 全栈开发
近两天内
