Vue项目中Axios的全面应用指南
1. 为什么Vue开发者需要掌握Axios
在Vue项目开发中,数据交互是不可或缺的核心环节。虽然现代浏览器提供了原生fetch API,但Axios作为专门为HTTP请求设计的库,在Vue生态中占据着不可替代的位置。这主要源于以下几个关键优势:
首先,Axios提供了完整的Promise API支持,这让异步代码的编写更加符合现代JavaScript的开发范式。与传统的回调函数相比,Promise链式调用和async/await语法能让代码逻辑更加清晰。例如,在Vue组件中我们可以这样优雅地处理请求:
async fetchUserData() { try { const response = await axios.get('/api/user'); this.userData = response.data; } catch (error) { console.error('获取用户数据失败:', error); this.showErrorToast(); } }其次,Axios内置了对请求和响应的拦截机制。这在企业级应用中尤为重要,我们可以通过拦截器统一处理身份认证、错误日志、请求/响应数据转换等通用逻辑。比如添加JWT认证头:
axios.interceptors.request.use(config => { const token = localStorage.getItem('auth_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; });第三,Axios具有完善的错误处理机制。不同于fetch需要手动检查响应状态码,Axios会自动将非2xx状态码视为错误,并提供了详细的错误对象,包含服务器响应数据、HTTP状态码等信息。这在调试和异常处理时提供了极大便利。
提示:虽然Vue 2时代常使用vue-resource,但Vue官方已明确推荐使用Axios。其活跃的社区维护和丰富的功能集使其成为Vue项目HTTP客户端的首选。
2. Axios核心配置与基础使用
2.1 安装与全局配置
在Vue项目中引入Axios通常有两种方式:直接通过npm安装或使用CDN引入。对于现代Vue项目,推荐使用npm/yarn安装:
npm install axios # 或 yarn add axios基础配置通常会在项目的src/utils/request.js文件中进行封装。一个典型的配置示例如下:
import axios from 'axios'; const service = axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL, // 从环境变量获取基础URL timeout: 10000, // 请求超时时间 headers: { 'Content-Type': 'application/json;charset=UTF-8' } }); export default service;2.2 请求方法与参数处理
Axios支持所有HTTP方法,最常用的包括:
- GET:获取数据
- POST:创建数据
- PUT:更新整个资源
- PATCH:部分更新资源
- DELETE:删除资源
GET请求的参数通常通过params传递,而POST等方法的请求体则通过data传递:
// GET请求示例 axios.get('/user', { params: { ID: 12345 } }); // POST请求示例 axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' });对于需要发送FormData的情况,可以这样处理:
const formData = new FormData(); formData.append('file', file); formData.append('name', 'test'); axios.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } });2.3 响应数据结构解析
Axios的响应对象包含以下重要属性:
{ data: {}, // 服务器返回的数据 status: 200, // HTTP状态码 statusText: 'OK', // 状态消息 headers: {}, // 响应头 config: {}, // 请求配置 request: {} // 生成此响应的请求 }在实际项目中,我们通常会根据后端接口规范对响应进行统一处理。例如,处理如下格式的响应:
{ code: 200, message: 'success', data: {...} // 实际业务数据 }可以在拦截器中这样处理:
service.interceptors.response.use( response => { const res = response.data; if (res.code !== 200) { // 处理业务错误 return Promise.reject(new Error(res.message || 'Error')); } return res.data; // 直接返回业务数据 }, error => { // 处理HTTP错误 return Promise.reject(error); } );3. Vue与Axios的深度集成实践
3.1 在Vue组件中使用Axios
在Vue组件中,我们通常会在methods中定义数据获取方法,并在生命周期钩子(如created或mounted)中调用。以下是典型示例:
export default { data() { return { posts: [], loading: false, error: null }; }, created() { this.fetchPosts(); }, methods: { async fetchPosts() { this.loading = true; try { const response = await axios.get('/api/posts'); this.posts = response.data; } catch (err) { this.error = err.message; } finally { this.loading = false; } } } };3.2 全局挂载与Vue原型扩展
为了在项目中更方便地使用Axios,可以将其挂载到Vue原型上:
// main.js import axios from 'axios'; Vue.prototype.$http = axios;这样在任何组件中都可以通过this.$http访问:
this.$http.get('/api/user').then(...);不过更推荐的做法是使用依赖注入,避免污染全局Vue实例:
// main.js import axios from 'axios'; const http = axios.create({...}); Vue.mixin({ beforeCreate() { this.$http = http; } });3.3 与Vuex的状态管理集成
在大型项目中,通常会将API调用与Vuex actions结合使用:
// store/modules/user.js const actions = { async fetchUser({ commit }, userId) { try { const response = await axios.get(`/users/${userId}`); commit('SET_USER', response.data); } catch (error) { commit('SET_ERROR', error.message); } } };对于需要处理分页等复杂状态的情况,可以使用如下模式:
async fetchPaginatedData({ commit, state }, { page, size }) { commit('SET_LOADING', true); try { const res = await axios.get('/data', { params: { page, size } }); commit('SET_DATA', { list: res.data.items, pagination: { total: res.data.total, current: page } }); } finally { commit('SET_LOADING', false); } }4. 高级特性与性能优化
4.1 取消请求与防抖处理
在某些场景下(如页面快速切换),我们需要取消未完成的请求以避免竞态条件。Axios提供了CancelToken机制:
const CancelToken = axios.CancelToken; let cancel; axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) { cancel = c; }) }); // 取消请求 cancel();对于搜索框等高频触发场景,可以结合防抖函数优化:
import _ from 'lodash'; export default { methods: { search: _.debounce(async function(query) { try { const res = await axios.get('/search', { params: { q: query } }); this.results = res.data; } catch (err) { console.error(err); } }, 500) } };4.2 并发请求与进度追踪
使用axios.all可以处理多个并发请求:
async fetchInitialData() { try { const [userRes, postsRes] = await axios.all([ axios.get('/user'), axios.get('/posts') ]); this.user = userRes.data; this.posts = postsRes.data; } catch (err) { // 处理错误 } }对于文件上传等需要显示进度的场景:
axios.post('/upload', formData, { onUploadProgress: progressEvent => { const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ); this.uploadProgress = percentCompleted; } });4.3 缓存策略与性能优化
实现简单的请求缓存可以显著提升应用性能:
const cache = new Map(); async function getWithCache(url) { if (cache.has(url)) { return cache.get(url); } const response = await axios.get(url); cache.set(url, response.data); return response.data; }对于关键API,可以结合localStorage实现持久化缓存:
async function fetchWithCache(key, url) { const cached = localStorage.getItem(key); if (cached) { return JSON.parse(cached); } const response = await axios.get(url); localStorage.setItem(key, JSON.stringify(response.data)); return response.data; }5. 常见问题与调试技巧
5.1 CORS问题解决方案
开发中常见的CORS问题可以通过以下方式解决:
- 后端配置正确的CORS头:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization- 开发环境配置代理(vue.config.js):
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } } };5.2 认证与CSRF防护
对于需要身份认证的API,通常需要在请求头中添加token:
axios.interceptors.request.use(config => { const token = store.state.user.token; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; });处理CSRF token(如Laravel应用):
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');5.3 错误处理最佳实践
完善的错误处理应该考虑多种情况:
axios.interceptors.response.use( response => response, error => { if (error.response) { // 服务器返回了非2xx的响应 switch (error.response.status) { case 401: // 处理未授权 router.push('/login'); break; case 403: // 处理禁止访问 showForbiddenMessage(); break; case 500: // 处理服务器错误 showServerError(); break; default: console.error('请求错误:', error); } } else if (error.request) { // 请求已发出但没有收到响应 console.error('网络错误:', error); } else { // 请求配置出错 console.error('配置错误:', error); } return Promise.reject(error); } );5.4 使用Vue Devtools调试
Vue Devtools可以很好地配合Axios进行调试:
- 在"Events"选项卡中查看组件触发的请求
- 使用"Timeline"记录请求时间线
- 结合console.log输出请求/响应数据
对于复杂场景,可以添加自定义日志:
axios.interceptors.request.use(config => { console.log('发起请求:', config.method, config.url); return config; }); axios.interceptors.response.use(response => { console.log('收到响应:', response.config.url, response.status); return response; });6. 实战案例:构建完整的CRUD应用
6.1 用户列表展示与分页
实现带分页的用户列表:
export default { data() { return { users: [], pagination: { current: 1, pageSize: 10, total: 0 }, loading: false }; }, methods: { async fetchUsers() { this.loading = true; try { const { current, pageSize } = this.pagination; const res = await axios.get('/users', { params: { page: current, size: pageSize } }); this.users = res.data.items; this.pagination.total = res.data.total; } finally { this.loading = false; } }, handlePageChange(page) { this.pagination.current = page; this.fetchUsers(); } }, created() { this.fetchUsers(); } };6.2 表单提交与数据验证
处理用户创建表单:
export default { data() { return { user: { name: '', email: '', password: '' }, rules: { name: [{ required: true, message: '请输入姓名' }], email: [ { required: true, message: '请输入邮箱' }, { type: 'email', message: '邮箱格式不正确' } ] } }; }, methods: { async submitForm() { try { await this.$refs.form.validate(); await axios.post('/users', this.user); this.$message.success('用户创建成功'); this.$router.push('/users'); } catch (err) { if (!err.response) { this.$message.error(err.message); } } } } };6.3 文件上传与进度显示
实现带进度条的文件上传:
export default { data() { return { file: null, uploadProgress: 0, isUploading: false }; }, methods: { handleFileChange(e) { this.file = e.target.files[0]; }, async uploadFile() { if (!this.file) return; const formData = new FormData(); formData.append('file', this.file); this.isUploading = true; this.uploadProgress = 0; try { await axios.post('/upload', formData, { onUploadProgress: e => { this.uploadProgress = Math.round((e.loaded * 100) / e.total); } }); this.$message.success('上传成功'); } finally { this.isUploading = false; } } } };6.4 实时数据更新策略
对于需要实时更新的数据,可以考虑以下几种方案:
- 轮询方式:
export default { data() { return { messages: [], pollInterval: null }; }, methods: { async fetchMessages() { const res = await axios.get('/messages'); this.messages = res.data; }, startPolling() { this.pollInterval = setInterval(this.fetchMessages, 5000); }, stopPolling() { clearInterval(this.pollInterval); } }, created() { this.fetchMessages(); this.startPolling(); }, beforeDestroy() { this.stopPolling(); } };- WebSocket结合Axios:
// 初始化WebSocket const socket = new WebSocket('ws://localhost:3000/updates'); socket.onmessage = async (event) => { const update = JSON.parse(event.data); if (update.type === 'new_message') { // 获取消息详情 const res = await axios.get(`/messages/${update.id}`); this.messages.push(res.data); } };7. 测试与Mock方案
7.1 单元测试中的Axios Mock
使用jest测试Axios请求:
import axios from 'axios'; import UserService from './UserService'; jest.mock('axios'); describe('UserService', () => { it('fetches user data', async () => { const mockUser = { id: 1, name: 'John Doe' }; axios.get.mockResolvedValue({ data: mockUser }); const user = await UserService.getUser(1); expect(user).toEqual(mockUser); expect(axios.get).toHaveBeenCalledWith('/users/1'); }); });7.2 使用MSW(Mock Service Worker)
MSW提供了更强大的Mock能力:
// src/mocks/handlers.js import { rest } from 'msw'; export const handlers = [ rest.get('/users', (req, res, ctx) => { return res( ctx.status(200), ctx.json({ items: [{ id: 1, name: 'John' }], total: 1 }) ); }) ]; // 测试文件中 import { setupServer } from 'msw/node'; import { handlers } from './handlers'; const server = setupServer(...handlers); beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close());7.3 开发环境Mock方案
对于开发环境,可以使用简单的JSON文件作为Mock数据:
// vue.config.js module.exports = { devServer: { before(app) { app.get('/api/users', (req, res) => { res.json(require('./mock/users.json')); }); } } };或者使用更专业的工具如json-server:
npm install -g json-server echo '{ "posts": [ { "id": 1, "title": "Axios指南" } ] }' > db.json json-server --watch db.json8. 安全最佳实践
8.1 敏感信息保护
避免在客户端存储敏感信息:
// 错误示例 - 直接暴露API密钥 axios.get('/data', { headers: { 'API-Key': 'your-secret-key' } }); // 正确做法 - 通过后端代理敏感请求 axios.get('/api/protected-data');8.2 HTTPS与安全头配置
确保生产环境使用HTTPS:
// 强制HTTPS if (process.env.NODE_ENV === 'production') { axios.defaults.baseURL = 'https://api.yourdomain.com'; }配置安全头:
axios.interceptors.request.use(config => { config.headers['X-Content-Type-Options'] = 'nosniff'; config.headers['X-Frame-Options'] = 'DENY'; return config; });8.3 请求限速与防滥用
实现简单的客户端限速:
const requestQueue = []; let isProcessing = false; async function processQueue() { if (isProcessing || requestQueue.length === 0) return; isProcessing = true; const { config, resolve, reject } = requestQueue.shift(); try { const response = await axios(config); resolve(response); } catch (error) { reject(error); } finally { isProcessing = false; setTimeout(processQueue, 1000); // 每秒处理一个请求 } } function rateLimitedRequest(config) { return new Promise((resolve, reject) => { requestQueue.push({ config, resolve, reject }); processQueue(); }); }9. 性能监控与分析
9.1 请求耗时监控
记录请求耗时并分析性能瓶颈:
axios.interceptors.request.use(config => { config.metadata = { startTime: Date.now() }; return config; }); axios.interceptors.response.use( response => { const duration = Date.now() - response.config.metadata.startTime; console.log(`请求 ${response.config.url} 耗时: ${duration}ms`); return response; }, error => { if (error.config) { const duration = Date.now() - error.config.metadata.startTime; console.error(`请求 ${error.config.url} 失败, 耗时: ${duration}ms`); } return Promise.reject(error); } );9.2 性能数据可视化
将性能数据发送到监控平台:
axios.interceptors.response.use( response => { const duration = Date.now() - response.config.metadata.startTime; trackApiPerformance({ url: response.config.url, method: response.config.method, duration, status: response.status }); return response; } );9.3 慢请求分析与优化
识别并优化慢请求:
const slowRequests = []; axios.interceptors.response.use( response => { const duration = Date.now() - response.config.metadata.startTime; if (duration > 1000) { // 超过1秒视为慢请求 slowRequests.push({ url: response.config.url, duration, timestamp: new Date().toISOString() }); } return response; } ); // 定期分析慢请求 setInterval(() => { if (slowRequests.length > 0) { console.warn('慢请求报告:', slowRequests); sendSlowRequestReport(slowRequests); slowRequests.length = 0; // 清空数组 } }, 60000);10. 项目架构与代码组织
10.1 API模块化设计
将API请求按业务模块组织:
src/ api/ auth.js # 认证相关API user.js # 用户相关API product.js # 产品相关API index.js # 统一导出示例user.js模块:
import request from '../utils/request'; export function getUser(id) { return request.get(`/users/${id}`); } export function createUser(data) { return request.post('/users', data); } export function updateUser(id, data) { return request.patch(`/users/${id}`, data); }10.2 类型定义与TypeScript集成
对于TypeScript项目,可以添加类型定义:
// types/api.d.ts declare interface ApiResponse<T> { code: number; message: string; data: T; } declare interface PaginatedData<T> { items: T[]; total: number; } // api/user.ts export interface User { id: number; name: string; email: string; } export async function getUsers( params: PaginationParams ): Promise<ApiResponse<PaginatedData<User>>> { return request.get('/users', { params }); }10.3 环境变量与多环境配置
管理不同环境的API配置:
# .env.development VUE_APP_API_BASE_URL=http://localhost:3000 VUE_APP_API_TIMEOUT=10000 # .env.production VUE_APP_API_BASE_URL=https://api.yourdomain.com VUE_APP_API_TIMEOUT=15000在axios配置中使用:
const service = axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL, timeout: parseInt(process.env.VUE_APP_API_TIMEOUT, 10) });11. 与第三方库的集成
11.1 结合Vue Router实现请求拦截
在路由跳转时取消未完成的请求:
// utils/request.js const pendingRequests = new Map(); axios.interceptors.request.use(config => { const requestKey = `${config.method}-${config.url}`; const cancelToken = new axios.CancelToken(cancel => { pendingRequests.set(requestKey, cancel); }); config.cancelToken = cancelToken; return config; }); axios.interceptors.response.use( response => { const requestKey = `${response.config.method}-${response.config.url}`; pendingRequests.delete(requestKey); return response; }, error => { if (axios.isCancel(error)) { console.log('请求被取消:', error.message); } return Promise.reject(error); } ); export function cancelPendingRequests() { pendingRequests.forEach((cancel, key) => { cancel(`路由切换取消请求: ${key}`); pendingRequests.delete(key); }); } // router.js router.beforeEach((to, from, next) => { cancelPendingRequests(); next(); });11.2 与UI框架(Element UI/Ant Design Vue)集成
结合Element UI的Loading和Message组件:
import { Loading, Message } from 'element-ui'; let loadingInstance; axios.interceptors.request.use(config => { if (config.showLoading !== false) { loadingInstance = Loading.service({ fullscreen: true, text: '加载中...' }); } return config; }); axios.interceptors.response.use( response => { if (loadingInstance) { loadingInstance.close(); } if (response.config.showSuccess !== false) { Message.success(response.data.message || '操作成功'); } return response; }, error => { if (loadingInstance) { loadingInstance.close(); } Message.error(error.response?.data?.message || '请求失败'); return Promise.reject(error); } );11.3 与图表库(ECharts)的数据集成
动态获取图表数据:
export default { data() { return { chart: null, chartOption: { // 基础配置 } }; }, async mounted() { this.initChart(); await this.fetchChartData(); }, methods: { initChart() { this.chart = echarts.init(this.$refs.chart); }, async fetchChartData() { try { const res = await axios.get('/chart-data'); this.updateChart(res.data); } catch (err) { console.error('获取图表数据失败:', err); } }, updateChart(data) { this.chart.setOption({ ...this.chartOption, series: [{ data: data.series }] }); } } };12. 未来演进与替代方案
12.1 Axios与现代Fetch API的比较
虽然Axios功能强大,但在某些场景下,原生fetch API可能是更轻量的选择:
| 特性 | Axios | Fetch API |
|---|---|---|
| 浏览器支持 | 需要polyfill | 现代浏览器原生支持 |
| 请求取消 | 支持 | 通过AbortController支持 |
| 超时设置 | 内置支持 | 需要手动实现 |
| 拦截器 | 内置支持 | 需要手动实现 |
| 请求/响应转换 | 内置支持 | 需要手动实现 |
| 自动JSON转换 | 是 | 需要手动调用.json() |
| 上传进度 | 支持 | 不支持 |
12.2 GraphQL与REST的选择
对于复杂的前端数据需求,可以考虑GraphQL作为替代方案:
import { ApolloClient, InMemoryCache } from '@apollo/client/core'; const client = new ApolloClient({ uri: '/graphql', cache: new InMemoryCache() }); // 查询示例 const { data } = await client.query({ query: gql` query GetUser($id: ID!) { user(id: $id) { id name posts { title } } } `, variables: { id: '1' } });12.3 WebSocket实时通信集成
对于实时性要求高的应用,可以结合WebSocket:
// socket.js class SocketService { constructor() { this.socket = null; this.listeners = new Map(); } connect() { this.socket = new WebSocket('wss://api.yourdomain.com/ws'); this.socket.onmessage = event => { const { type, data } = JSON.parse(event.data); const handlers = this.listeners.get(type) || []; handlers.forEach(handler => handler(data)); }; } on(eventType, handler) { if (!this.listeners.has(eventType)) { this.listeners.set(eventType, []); } this.listeners.get(eventType).push(handler); } } export const socketService = new SocketService(); // 在组件中使用 import { socketService } from './socket'; export default { created() { socketService.connect(); socketService.on('new_message', this.handleNewMessage); }, methods: { handleNewMessage(message) { this.messages.push(message); } } };13. 项目实战:电商平台API集成
13.1 商品列表与搜索实现
export default { data() { return { products: [], searchQuery: '', filters: { category: '', priceRange: [0, 1000] }, pagination: { current: 1, pageSize: 12, total: 0 } }; }, methods: { async fetchProducts() { const params = { q: this.searchQuery, category: this.filters.category, minPrice: this.filters.priceRange[0], maxPrice: this.filters.priceRange[1], page: this.pagination.current, size: this.pagination.pageSize }; const res = await axios.get('/products', { params }); this.products = res.data.items; this.pagination.total = res.data.total; }, handleSearch() { this.pagination.current = 1; this.fetchProducts(); } }, created() { this.fetchProducts(); } };13.2 购物车管理
export default { methods: { async addToCart(productId, quantity = 1) { try { await axios.post('/cart/items', { productId, quantity }); this.$message.success('已加入购物车'); this.fetchCart(); } catch (err) { this.$message.error('添加失败'); } }, async updateCartItem(itemId, quantity) { if (quantity < 1) { await this.removeCartItem(itemId); return; } await axios.patch(`/cart/items/${itemId}`, { quantity }); this.fetchCart(); }, async removeCartItem(itemId) { await axios.delete(`/cart/items/${itemId}`); this.fetchCart(); } } };13.3 订单创建与支付流程
export default { methods: { async createOrder(cartItems, shippingInfo) { const orderItems = cartItems.map(item => ({ productId: item.product.id, quantity: item.quantity })); const res = await axios.post('/orders', { items: orderItems, shipping: shippingInfo }); return res.data.id; // 返回订单ID }, async getPaymentMethods(orderId) { const res = await axios.get(`/orders/${orderId}/payment-methods`); return res.data; }, async processPayment(orderId, paymentMethod) { const res = await axios.post(`/orders/${orderId}/payments`, { method: paymentMethod }); if (res.data.redirectUrl) { window.location.href = res.data.redirectUrl; } } } };14. 移动端适配与优化
14.1 请求重试机制
针对移动网络不稳定的优化:
axios.interceptors.response.use( response => response, async error => { const config = error.config; // 设置重试次数,默认为3次 config.__retryCount = config.__retryCount || 0; // 检查是否达到最大重试次数 if (config.__retryCount >= 3) { return Promise.reject(error); } // 增加重试计数器 config.__retryCount += 1; // 创建新的Promise来处理指数退避 const delay = new Promise(resolve => { setTimeout(() => resolve(), 1000 * config.__retryCount); }); // 返回Promise,在延迟后重试请求 await delay; return axios(config); } );14.2 离线缓存策略
实现基本的离线缓存:
const cacheName = 'api-cache-v1'; async function fetchWithCache(url) { // 检查缓存 const cached = localStorage.getItem(`cache:${url}`); if (cached) { return JSON.parse(cached); } try { // 发起网络请求 const response = await axios.get(url); // 缓存响应数据 localStorage.setItem( `cache:${url}`, JSON.stringify({ data: response.data, timestamp: Date.now() }) ); return response.data; } catch (error) { // 网络请求失败时检查是否有过期缓存可用 const staleCache = localStorage.getItem(`cache:${url}`); if (staleCache) { const { data } = JSON.parse(staleCache); console.warn('使用过期缓存数据'); return data; } throw error; } }14.3 数据压缩与优化
减少移动端数据传输量:
// 请求压缩 axios.interceptors.request.use(config => { if (config.data && config.compress !== false) { config.data = compressData(config.data); config.headers['Content-Encoding'] = 'gzip'; } return config; }); // 响应解压 axios.interceptors.response.use( response => { if (response.headers['content-encoding'] === 'gzip') { response.data = decompressData(response.data); } return response; } );15. 服务端渲染(SSR)中的特殊处理
15.1 避免请求重复
在Nuxt.js中避免客户端和服务器端重复请求:
// 插件: ~/plugins/axios.js export default function({ $axios, store }) { // 服务器端请求时设置baseURL if (process.server) { $axios.defaults.baseURL = 'http://localhost:3000'; } // 将服务端获取的数据注入到客户端 if (process.client) { const data = window.__NUXT__.state; if (data) { store.replaceState(data); } } } // 页面组件中使用asyncData export default { async asyncData({ $axios }) { const { data } = await $axios.get('/api/posts'); return { posts: data }; } };15.2 处理认证状态
在SSR中正确处理认证:
// middleware/auth.js export default function({ $axios, req, store }) { // 服务器端从请求头获取token if (process.server) { const token = req.headers.cookie?.split(';') .find(c => c.trim().startsWith('auth_token=')) ?.split('=')[1]; if (token) { $axios.setToken(token, 'Bearer'); store.commit('auth/setToken', token); } } // 客户端拦截器 $axios.onRequest(config => { const token = store.state.auth.token; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); }15.3 错误处理与状态码
SSR中的特殊错误处理:
// nuxt.config.js export default { axios: { proxy: true, retry: false, // 禁用自动重试 https: process.env.NODE_ENV === 'production' }, proxy: {