前后端交互是现代 Web 应用中最核心的环节之一,涉及请求封装、跨域处理、认证鉴权和数据缓存等多个方面。一个设计良好的 HTTP 交互层可以显著提升开发效率和代码可维护性。本文将系统梳理前后端交互的关键技术点。
Axios 企业级封装
直接使用 axios 发起请求会导致大量重复代码。一个规范的封装应该覆盖 Token 注入、请求签名、统一错误处理、请求重试和 Token 刷新等能力。
// utils/request.ts\nimport axios from 'axios';\nconst service = axios.create({\n baseURL: import.meta.env.VITE_API_BASE_URL,\n timeout: 15000,\n withCredentials: true,\n});\n\n// 请求拦截器\nservice.interceptors.request.use((config) => {\n const userStore = useUserStore();\n if (userStore.token) {\n config.headers.Authorization = `Bearer ${userStore.token}`;\n }\n // 时间戳防缓存(GET 请求)\n if (config.method === 'get') {\n config.params = { ...config.params, _t: Date.now() };\n }\n return config;\n});\n\n// 响应拦截器\nservice.interceptors.response.use(\n (response) => {\n const { code, data, message } = response.data;\n if (code === 200) return data;\n if (code === 401) { useUserStore().logout(); router.push('/login'); }\n return Promise.reject(new Error(message));\n },\n (error) => {\n if (error.message.includes('timeout')) ElMessage.error('请求超时');\n return Promise.reject(error);\n }\n);跨域问题:从原理到解决方案
为什么会有跨域?
浏览器的同源策略(Same-Origin Policy)要求协议、域名、端口三者完全一致才允许访问。这是浏览器的安全机制,防止恶意网站窃取数据。需要注意的是,跨域限制是浏览器的行为,服务端之间的请求不受限制。
方案一:CORS(后端配置,最主流)
// SpringBoot 配置\n@Configuration\npublic class CorsConfig implements WebMvcConfigurer {\n @Override\n public void addCorsMappings(CorsRegistry registry) {\n registry.addMapping("/**")\n .allowedOriginPatterns("*")\n .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")\n .allowedHeaders("*")\n .allowCredentials(true)\n .maxAge(3600);\n }\n}方案二:开发环境代理(Vite 配置,最常用)
// vite.config.ts\nserver: {\n proxy: {\n '/api': { target: 'http://localhost:8080', changeOrigin: true }\n }\n}方案三:Nginx 反向代理(生产环境首选)
前端和后端部署在同一域名下,通过 Nginx 将 /api/ 路径代理到后端服务,彻底避免跨域问题。
Token 认证机制深度对比
JWT(JSON Web Token)
JWT 由三部分组成(Header.Payload.Signature),每部分用 Base64 编码。后端签发后,前端存储在 localStorage 或 cookie 中,每次请求携带在 Authorization 头中。
JWT 的核心争议:无状态 vs 不可撤销。JWT 签发后服务端无法主动使其失效——如果你的 access_token 有效期是 2 小时,那么即使你在第 1 分钟就退出登录,攻击者拿到这个 token 后仍可在剩余的 1 小时 59 分内使用它。解决方案:短 access_token + 长 refresh_token(access_token 有效期 15-30 分钟,refresh_token 有效期 7-30 天)或 Token 黑名单(在 Redis 中维护已注销 token 的黑名单)。
无感刷新 Token 机制(关键)
let isRefreshing = false;\nlet refreshSubscribers = [];\n\nservice.interceptors.response.use(\n (response) => response,\n async (error) => {\n const { config, response } = error;\n if (response?.status !== 401 || config._retry) return Promise.reject(error);\n if (!isRefreshing) {\n isRefreshing = true;\n const { token } = await refreshToken();\n isRefreshing = false;\n refreshSubscribers.forEach(cb => cb(token));\n refreshSubscribers = [];\n return service(config); // 用新 token 重试\n }\n return new Promise((resolve) => {\n refreshSubscribers.push((newToken) => {\n config.headers.Authorization = `Bearer ${newToken}`;\n resolve(service(config));\n });\n });\n }\n);前端缓存策略
| 缓存类型 | 存储位置 | 容量 | 过期策略 | 适用场景 |
|---|---|---|---|---|
| localStorage | 浏览器 | 5MB | 手动清除 | 用户偏好、主题设置 |
| sessionStorage | 浏览器 | 5MB | 关闭标签页时清除 | 表单草稿、临时状态 |
| Cookie | 浏览器/服务端 | 4KB | 可设过期时间 | Token 存储、会话标识 |
| IndexedDB | 浏览器 | 无上限 | 手动管理 | 大量结构化数据、离线应用 |
| HTTP 缓存 | 浏览器/代理 | 由响应头控制 | Cache-Control 头 | 静态资源缓存 |
总结
前后端交互的核心设计原则:请求层统一封装,不要散落在各处;认证机制无感刷新,用户登录一次便不再被打断;错误处理统一收敛,不要让每个调用方都写 try-catch;缓存策略分层设计,该缓存的绝不重复请求。
评论 (0)