从接口文档到前端调用:Axios 封装与实战全流程详解

文章目录

从接口文档到前端调用:Axios 封装与实战全流程详解

1.如何看接口文档?

在一个接口文档中,有很多的请求类型(也叫 HTTP 方法 / 动作)

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

这里仅以 GET 和 POST 做讲解,其他的请求类型,都类似

1.1 GET

注意:GET 跟 URL 息息相关

来看一个具体的例子:

首先,接口都会有一个 baseUrl,作为获取数据的地址,使用不同的接口时,又会有不同的路径,比如这个就是/my/cate/info

第一部分:请求参数(Request Parameters)

Query 参数和 Header 参数

Query 参数和 Header 参数

query 跟 url 息息相关

header 跟身份验证相关,就是说,想让这个请求发送给接口,必须满足一些条件,header 就像一把钥匙

文档中这两部分都必须传对,否则接口要么报错,要么不给你数据。

  1. Query 参数
  • 出现在 URL 上。

  • 在这个接口里:

    复制代码
    GET /my/cate/info?id=1284

    这里的 id=1284 就是 文章分类的 id,告诉后台我要取哪一个分类的详情。

  • 所以:Query 参数就是用来指定查询条件的

  1. Header 参数
  • 放在 HTTP 请求的 请求头里。
  • 这里要求的参数是:
    • Authorization: Bearer <token>

Authorization:英语中授权的意思

  • 作用:用来验证用户身份(你是否已经登录)。
  • 也就是说:
    • 如果没有这个 token → 后台会返回 401 身份认证失败
    • 有正确 token → 才能拿到分类详情。

第二部分:响应(Response)

javascript 复制代码
{
  "code": 0,
  "message": "获取文章分类成功!",
  "data": {
    "id": 1070,
    "cate_name": "科技",
    "cate_alias": "keji"
  }
}
  • code :业务状态码。
    • 0 表示成功,1 表示异常。
  • message:提示消息(给人看的,比如"成功/失败原因")。
  • data :真正的业务数据,这里是文章分类的详情对象。
    • id:分类 ID。
    • cate_name:分类名称(比如 "科技")。
    • cate_alias:分类别名(比如 "keji")。

这部分就是告诉你:调用成功以后,后台会返回什么样的数据结构,你前端代码里就可以用这些字段来展示页面。

1.2 POST

看如下例子:返回响应部分不做介绍,POST 请求方法没有 Query 参数,而是 Body 参数

Body 参数(请求体)

这是 POST 接口的重点,和 GET 很不同:

  • 位置 :请求报文的 body 部分,不在 URL 上。
  • 格式 :这里文档写了 application/json,说明 body 要用 JSON 格式。
  • 作用 :用来传递 新增数据的内容

在文档里,它定义了两个字段:

  1. cate_name (string)
    • 文章分类名字,比如"娱乐"、"科技"。
    • 必填,长度限制:1--10 个非空字符。
  2. cate_alias (string)
    • 文章分类别名,比如"yule"、"keji"。
    • 必填,长度限制:1--15 个大小写字母和数字组合。

示例 JSON

复制代码
{
  "cate_name": "娱乐",
  "cate_alias": "yule"
}

为什么 GET 没有 Body,而 POST 要用 Body?

GET:只是获取数据,不修改,所以参数少,放 URL 上即可。

POST:要创建一条新数据,通常包含多个字段(标题、别名、内容......),如果写在 URL 会很长很乱,所以必须放到 Body 里,结构化成 JSON。

2.为什么要封装请求拦截器和响应拦截器?如何封装?

简单来说,实际开发过程中,不能每一次都手动的在请求头中加入授权的 token,而请求拦截器,会拦截请求将每个授权的 token 加入到本次的请求头当中.

统一封装 axios 请求模板:

官方文档:https://www.axios-http.cn/docs/interceptors

javascript 复制代码
import axios from 'axios'

const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  // 1. 基础地址,超时时间(配置项)
})

//请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 2. 携带token,将 token 值赋给请求头
    return config
  },
  (err) => Promise.reject(err)
)

//响应拦截器
instance.interceptors.response.use(
//http 返回 200 成功
  (res) => {  
    // 3. 正确拿到了业务数据
    
    // 4. 业务逻辑错误,例如限制密码字母大写
    return res
  },
  (err) => {
    // 5. 处理http 返回401错误
    return Promise.reject(err)
  }
)

export default instance
  • 将封装写在 src/utils/request.js
  • 首先,创建一个 axios 实例
  • 其次,写出请求拦截器和响应拦截器

2.1 封装axios实例

(1)统一配置

  • 每个接口都要用到的公共参数,比如:
    • baseURL(基础路径)
    • timeout(超时时间)
    • headers(请求头,常常要放 token)
  • 如果不封装,每次 axios.get() / axios.post() 都要手动写,很麻烦。
  • 封装后 → 写一次,所有请求自动带上。

timeout:请求超过 x 毫秒 还没响应,就自动报错,进入 .catch()

请求中几乎所有接口都需要,而且不会频繁变化 的东西,适合直接写在 axios.create()headers 里,所以 token 不应该写在这里,token 应写在拦截器中

(2)更好的可维护性

  • 以后如果 baseURL 要改(比如从测试环境 → 正式环境),只需要改 request.js 这一处。
  • 如果不封装,你得在项目里到处找 URL,一个个修改,容易遗漏。

(3)添加请求/响应拦截器

(4)支持多实例

有些项目里:

  • 一部分接口走 https://api.example.com
  • 另一部分接口走 https://upload.example.com
    就可以创建两个不同的 axios 实例,互不影响。

封装axios实例代码如下:

javascript 复制代码
import axios from 'axios'
const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  baseURL,
  timeout: 100000
})

2.2 封装拦截器

官方文档中的拦截器

javascript 复制代码
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

分析:

request 拦截器的代码是一样的,关键在于拿到的对象不一样,一个是 config,一个是 response

  • config 对象
    • axios 会先把你传入的参数转成一个"配置对象",这个配置对象就是 config 对象
  • response 对象
    • 浏览器原生的 XHR 或 fetch 会产生一个响应结果,axios 会把这个结果"包装"成一个对象

注意:

  • 这里的 axios.替换成你对应的 axios 实例
  • function(config) 也可以替换成对应的箭头函数()=>{}

2.3 拦截器实践

请求拦截器:使用 pinia 存储的 token,将 token 值赋给请求头

javascript 复制代码
instance.interceptors.request.use(
  (config) => {
    const userStore = useUserStore()
    if (userStore.token) {
      config.headers.Authorization = userStore.token
    }
    return config
  },
  (err) => Promise.reject(err)

响应拦截器:

  • 成功拿到响应,直接返回,没拿到服务异常

  • 若错误,根据错误类型提示或跳转路由

javascript 复制代码
instance.interceptors.response.use(
  (res) => {
    if (res.data.code === 0) {
      return res
    }
    ElMessage({ message: res.data.message || '服务异常', type: 'error' })
    return Promise.reject(res.data)
  },
  (err) => {
    ElMessage({ message: err.response.data.message || '服务异常', type: 'error' })
    console.log(err)
    if (err.response?.status === 401) {
      router.push('/login')
    }
    return Promise.reject(err)
  }
)

导出

javascript 复制代码
export default instance
export { baseURL }

3.如何在实际的项目中使用axios

3.1 GET

无需请求参数的 GET

在 src/api 下创建自定义的 js 文件,如 article.js.存放跟文章相关的 api

src/api/article.js

  • 导入封装好的方法
javascript 复制代码
import request from '@/utils/request'
  • 实现 api
javascript 复制代码
//获取文章分类
export const artGetChannelsService=()=>request.get('/my/cate/list')
  • 在具体的.vue 文件中使用

    • 导入该方法

      javascript 复制代码
      import { artGetChannelsService} from '@/api/article'
    • 使用该方法

      javascript 复制代码
       const res =await artGetChannelsService()

需要请求参数的 GET

API 封装:

javascript 复制代码
// 获取文章分类详情 ?id=xxx
export const artGetChannelDetailService = (id) => {
  return request.get('/my/cate/info', {
    params: { id }          // => /my/cate/info?id=1284
  })
}

为什么写 params 呢?

因为能拼到 url 后面

在 .vue 里使用:

javascript 复制代码
import { artGetChannelDetailService } from '@/api/article'

const id = route.query.id   // 比如路由里带着 ?id=1284
await artGetChannelDetailService(id)

3.2 POST

以这个为例:

  • 导入封装好的方法
javascript 复制代码
import request from '@/utils/request'
  • 实现 api
javascript 复制代码
//添加文章分类
export const artAddChannelService=(data)=>request.post('/my/cate/add',data)

  • 在具体的.vue 文件中使用

    • 导入该方法

      javascript 复制代码
      import { artAddChannelService} from '@/api/article'
    • 使用该方法,此时注意了,POST 是需要我们传参的

      javascript 复制代码
      //定义表单数据
      const formModel=ref({
          cate_name:'',
          cate_alias:''
      })
      
      await artAddChannelService(formModel.value)

3.3. DELETE

Delete 也是需要一个请求参数,写法跟带参数的 GET 一样

API 封装:

javascript 复制代码
// 删除文章分类
export const artDelChannelService = (id) =>
  request.delete('/my/cate/del', {
    params: { id }
  })

3.4 PUT

put 跟 post 写法一样,除了 request 方法是 put

API 封装:

javascript 复制代码
export const artEditChannelService =(data)=> request.put('/my/cate/info',data)

在实际写法中,也可以不用形参 data,直接传对象,比如

javascript 复制代码
//更新个人信息
export const userUpdateInfoService = ({ id, nickname, email }) =>
  request.put('/my/userinfo', { id, nickname, email })

3.5 PATCH

API 封装:

跟 post 一样

javascript 复制代码
//上传头像
export const userUploadAvatarService = (avatar) => request.patch('/my/update/avatar', { avatar })
相关推荐
子春一24 分钟前
Flutter 2025 可访问性(Accessibility)工程体系:从合规达标到包容设计,打造人人可用的数字产品
前端·javascript·flutter
白兰地空瓶11 分钟前
别再只会调 API 了!LangChain.js 才是前端 AI 工程化的真正起点
前端·langchain
jlspcsdn1 小时前
20251222项目练习
前端·javascript·html
行走的陀螺仪1 小时前
Sass 详细指南
前端·css·rust·sass
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 小时前
React 怎么区分导入的是组件还是函数,或者是对象
前端·react.js·前端框架
LYFlied2 小时前
【每日算法】LeetCode 136. 只出现一次的数字
前端·算法·leetcode·面试·职场和发展
子春一22 小时前
Flutter 2025 国际化与本地化工程体系:从多语言支持到文化适配,打造真正全球化的应用
前端·flutter
QT 小鲜肉2 小时前
【Linux命令大全】001.文件管理之file命令(实操篇)
linux·运维·前端·网络·chrome·笔记
羽沢313 小时前
ECharts 学习
前端·学习·echarts