×

Axios是啥?和Vue搭配为啥流行?

作者:Terry2025.12.16来源:Web前端之家浏览:48评论:0
关键词:AxiosVue

在Vue项目里做数据请求,Axios几乎是绕不开的工具,但新手刚接触时,总会碰到“怎么引入?请求咋写?跨域咋解决?”这些问题,这篇文章把Vue和Axios结合时的常见问题拆成一个个小问题,从基础用法到实战优化,一步步讲清楚,帮你把Axios用得顺手~

Axios是个基于Promise的HTTP客户端,既能在浏览器里发请求(处理浏览器的XMLHttpRequest),也能在Node.js环境用(基于http模块),它和Vue搭配流行,核心是这几点:   - **和Vue的异步逻辑契合**:Vue里常用的`async/await`、生命周期钩子(created`里发请求),和Axios的Promise风格天然适配,写异步代码更丝滑;   - **拦截器是“神助攻”**:能在请求发出去前、响应回来后“插一脚”——比如请求前统一加token、响应后统一处理错误,不用每个请求重复写逻辑;   - **上手门槛低**:API设计简单,`get` `post`这些方法一看就懂,还能灵活配置超时、请求头,对前端同学友好。

Vue项目里咋引入Axios?

分“全局挂载”和“实例化”两种思路,按需选:

方式1:全局挂载(简单直接)

先装依赖:用npm install axios或者yarn add axios把Axios装到项目里。
然后在Vue的入口文件(比如main.js)里全局注册:

import Vue from 'vue'
import axios from 'axios'
// 把axios挂到Vue原型上,所有组件都能通过this.$axios调用
Vue.prototype.$axios = axios

之后在组件里就能直接用了,比如在created钩子发请求:

export default {
  created() {
    this.$axios.get('/api/users').then(res => {
      console.log(res.data)
    })
  }
}

方式2:实例化(灵活配置多环境)

如果项目有多个不同域名的接口(比如开发、测试、生产环境),或者需要不同的超时、请求头,可以创建自定义Axios实例

import axios from 'axios'
// 创建实例,配置基地址、超时等
const service = axios.create({
  baseURL: 'https://api.example.com', // 接口基地址
  timeout: 5000, // 请求超时时间(毫秒)
  headers: { 'X-Custom-Header': 'xxx' } // 自定义请求头
})
// 把实例导出,组件里按需导入
export default service

这样不同模块能复用不同实例,比如用户模块用userService,商品模块用goodsService,彼此配置互不影响。

最基础的GET/POST请求咋写?

async/await(推荐,代码更简洁)或者.then()都能写,举两个常用场景:

GET请求(带查询参数)

比如获取用户列表,需要传pagesize参数:

async getUsers() {
  try {
    // params里的参数会自动拼到url后面(?page=1&size=10)
    const res = await this.$axios.get('/users', {
      params: { page: 1, size: 10 }
    })
    this.userList = res.data // 把响应数据存到组件data里
  } catch (err) {
    console.error('请求失败:', err)
  }
}

POST请求(传请求体)

比如新增用户,要把用户信息传到后端:

async addUser() {
  const userInfo = { name: '小明', age: 20 }
  try {
    // data里的内容会放到请求体(Request Body)里
    const res = await this.$axios.post('/users', userInfo)
    if (res.data.code === 200) { // 假设后端返回code=200代表成功
      this.$toast('添加成功~') // 用UI库提示成功
    }
  } catch (err) {
    this.$toast('添加失败,请重试~')
  }
}

拦截器有啥用?咋配置?

拦截器就像“中间件”,能在请求发出去前响应回来后做统一处理,避免重复代码。

请求拦截器:加token、开loading

比如每个请求都要带用户token,或者发请求时显示“加载中”:

// 给全局axios加请求拦截器
axios.interceptors.request.use(
  config => {
    // 1. 加token:从localStorage取token,塞到请求头
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    // 2. 开loading:比如用Element UI的Loading组件
    // Loading.service({ fullscreen: true })
    return config // 必须返回config,请求才会继续
  },
  error => {
    // 请求配置出错时(比如url写错),直接拒绝
    return Promise.reject(error)
  }
)

响应拦截器:解包数据、统一错误处理

后端返回的数据可能包了一层(比如{ code, data, msg }),或者要处理401、500这些错误:

axios.interceptors.response.use(
  response => {
    // 1. 关loading
    // Loading.service().close()
    // 2. 解包数据:只返回业务需要的data
    return response.data 
  },
  error => {
    // 处理错误:比如401跳登录,500提示服务器错误
    if (error.response.status === 401) {
      router.push('/login') // 跳转到登录页
    } else {
      // 用UI库提示错误信息
      Message.error(error.response.data.msg || '服务器开小差啦~')
    }
    return Promise.reject(error) // 把错误抛给组件
  }
)

注意:如果用了自定义实例(比如前面的service),拦截器要挂在实例上:service.interceptors.request.use(...)  

跨域问题咋解决?开发和生产不一样咋办?

浏览器有“同源策略”(协议、域名、端口必须一致才算同源),前端发请求到不同源的后端就会跨域,分开发阶段生产阶段处理:

开发阶段:用Vue CLI代理

vue.config.js里配置devServer.proxy,把前端请求“代理”到后端域名:

module.exports = {
  devServer: {
    proxy: {
      '/api': { // 匹配以/api开头的请求
        target: 'https://api.example.com', // 后端真实地址
        changeOrigin: true, // 开启跨域(让后端以为请求来自自己的域名)
        pathRewrite: { '^/api': '' } // 把/api替换成空,比如请求/api/users → 实际发往https://api.example.com/users
      }
    }
  }
}

这样前端请求时,用/api开头就不会跨域,比如this.$axios.get('/api/users')

生产阶段:后端开CORS或Nginx代理

  • 后端开CORS:后端在响应头加Access-Control-Allow-Origin: *(或指定前端域名),前端不用改代码,浏览器就允许跨域请求;

  • Nginx反向代理:把前端和后端部署在同一域名下,用Nginx转发请求,比如前端部署在example.com,后端接口是api.example.com,Nginx配置把/example-api请求转发到api.example.com,前端请求/example-api/users就不会跨域。

重复请求和竞态问题咋处理?

用户快速点按钮、多次发同一请求,或者请求A和请求B顺序乱了,都会导致问题,这两种场景要分开处理:

场景1:重复请求(比如快速点按钮)

AbortController(现代浏览器支持)取消之前的请求:

let abortController = null // 存当前请求的控制器
async function fetchData() {
  if (abortController) {
    abortController.abort() // 取消上一次请求
  }
  abortController = new AbortController() // 新建控制器
  try {
    const res = await axios.get('/data', {
      signal: abortController.signal // 把信号传给请求
    })
    // 处理响应数据
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('上一次请求被取消啦~')
    } else {
      console.error('真的出错了:', err)
    }
  }
}

场景2:竞态问题(请求顺序乱了)

比如先搜“苹果”再搜“香蕉”,但“苹果”的请求后返回,导致页面显示错误,解决思路:

  • 用时间戳标记请求:每次发请求时记录时间戳,只处理最后一次请求的响应;

  • 组件销毁时取消请求:在Vue的beforeDestroy钩子里,取消还没完成的请求;

  • 防抖/节流:比如搜索框输入时,用户停止输入1秒后再发请求,避免每次输入都发请求。

错误处理咋做更友好?

用户最讨厌“请求失败”却不知道为啥失败,要区分网络错误业务错误(比如参数错)、服务器错误,给明确反馈:

全局统一处理(响应拦截器)

在响应拦截器里写通用错误逻辑,比如前面讲的响应拦截器示例,能覆盖大部分错误,再封装个函数,把错误类型拆细:

function handleError(error) {
  if (error.response) {
    // 服务器返回错误(状态码不是2xx)
    const { status, data } = error.response
    if (status === 400) {
      Message.error(data.msg || '参数填错啦~')
    } else if (status === 500) {
      Message.error('服务器忙,稍等再试~')
    }
  } else if (error.request) {
    // 请求发出去了,但没收到响应(比如断网)
    Message.error('网络开小差了,检查下WiFi?')
  } else {
    // 其他错误(比如配置错)
    Message.error('请求配置出错:' + error.message)
  }
}

组件内兜底处理

在组件里用try...catch或者.catch(),兜底捕获没被全局拦截的错误:

async getInfo() {
  try {
    const res = await this.$axios.get('/info')
    this.info = res.data
  } catch (err) {
    handleError(err) // 调用全局错误处理函数
  }
}

怎么封装Axios更高效?

项目大了,每个请求都写axios.get axios.post会很冗余,封装后,统一配置、统一错误处理,维护起来更爽:

步骤1:创建实例+配置拦截器

utils/request.js里写:

import axios from 'axios'
import { Message } from 'element-ui' // 假设用Element UI的提示
// 创建自定义实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // 从环境变量取基地址(不同环境不同值)
  timeout: 10000, // 超时时间
  headers: { 'Content-Type': 'application/json;charset=utf-8' }
})
// 请求拦截器:加token
service.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)
// 响应拦截器:解包+错误处理
service.interceptors.response.use(
  response => {
    const res = response.data
    if (res.code !== 200) { // 假设业务成功码是200
      Message.error(res.msg || '操作失败')
      return Promise.reject(new Error(res.msg || 'Error'))
    }
    return res // 只返回业务数据
  },
  error => {
    handleError(error) // 调用前面的错误处理函数
    return Promise.reject(error)
  }
)

步骤2:封装通用请求方法

get post这些方法封装好,组件里直接导入用:

// 封装get请求
export function get(url, params) {
  return service.get(url, { params })
}
// 封装post请求
export function post(url, data) {
  return service.post(url, data)
}
// 其他请求方法(put、delete等)同理

步骤3:组件里用封装后的方法

比如用户模块的组件:

import { get, post } from '@/utils/request' // 导入封装的方法
export default {
  data() {
    return { userList: [] }
  },
  async created() {
    // 获取用户列表
    const res = await get('/users', { page: 1, size: 10 })
    this.userList = res.data
  },
  methods: {
    async addUser() {
      const user = { name: '小红', age: 22 }
      await post('/users', user)
      this.$toast('添加成功~')
    }
  }
}

这样封装后,后期要改基地址、超时时间,只需要改utils/request.js,不用每个组件到处找请求代码,维护性拉满~

吃透上面这些问题,Vue项目里的Axios基本就“玩得转”了,从基础请求到拦截器、跨域、错误处理再到封装,每一步都是开发里高频遇到的场景,把这些逻辑理顺,不仅写代码效率高,用户体验也会更流畅~

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://www.jiangweishan.com/article/Axios-Vue-sdfsd.html

网友评论文明上网理性发言 已有0人参与

发表评论: