Axios超简单使用文档
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端 json-server 可能很多人并不会写后端,也可能没有一个可以用的后端接口地址 没关系,咱们自己造一个
Axios超简单使用文档
发布时间:2023-11-13 (2023-11-13)

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端

json-server

可能很多人并不会写后端,也可能没有一个可以用的后端接口地址

没关系,咱们自己造一个

json-server就是一个可以快速在json文件的基础上,起六个增删改改查查的六个接口

使用json-server先简单起一个服务

npm i -g json-server

db.json

{
  "users": [
    {
      "id": 1,
      "name": "枫枫",
      "age": 21,
      "addr": "湖南省长沙市"
    },
    {
      "id": 2,
      "name": "张三",
      "age": 22,
      "addr": "四川省成都市"
    }
  ]
}

运行服务

json-server -w db.json
# 增
POST  http://localhost:3000/users
{
    "name": "枫枫",
    "age": 22,
    "addr": "湖南省长沙市"
} 
## id自动增长
# 删
DELETE  http://localhost:3000/users/3
# 改  全字段更新,不传就删除
PUT  http://localhost:3000/users/3
{
    "name": "枫枫1",
    "age": 22
} 
# 改  单字段更新,传什么更什么
PATCH  http://localhost:3000/users/3
{
    "name": "枫枫2",
} 
# 查列表
GET  http://localhost:3000/users
# 查详情
GET  http://localhost:3000/users/1

axios使用

html模式

很多人可能也不会用vue的脚手架,没关系,会新建html就行了

<!doctype html>
<html lang="ch">
<head>
    <meta charset="UTF-8">
    <title>Axios使用</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
    axios.get("http://localhost:3000/users").then(res => {
        console.log(res.data)
    })
</script>
</body>
</html>

打开控制台就能看到列表的json里面的数据了

后面的一些操作都是通用的

vue3项目中使用

npm init vue@latest

注意:本教程只是讲解axios,所以没勾vue-router和pinia

安装axois

npm i axios
<template>

</template>

<script setup lang="ts">
import axios from "axios";

axios.get("http://localhost:3000/users").then(res => {
  console.log(res.data)
})


</script>

axios增删改查

<template>
  <div>
    <table>
      <thead>
      <tr>
        <th>id</th>
        <th>用户名</th>
        <th>年龄</th>
        <th>地址</th>
        <th>操作</th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="item in data.list" :key="item.id">
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.age }}</td>
        <td>{{ item.addr }}</td>
        <td>
          <button @click="detailData(item.id as number)">详情</button>
          <button @click="putData(item)">修改</button>
          <button @click="deleteData(item)">删除</button>
        </td>
      </tr>
      </tbody>
    </table>
    <button @click="create">新增一条</button>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import {reactive} from "vue";
import type {AxiosResponse} from "axios";

const url: string = "http://localhost:3000/users/"

interface jsonData {
  readonly id?: number
  name: string
  age: number
  addr?: string
}

interface Data {
  list: jsonData[]
}

const data = reactive<Data>({
  list: []
})

// 请求列表
async function getData() {
  let res: AxiosResponse<jsonData[]> = await axios.get(url)
  data.list = res.data
}

// 增加数据
async function create() {
  let body: jsonData = {
    name: "王五",
    age: 23,
    addr: "北京市",
  }
  let res = await axios.post(url, body)
  console.log("新增", res.data)
  getData()
}

// 修改数据 年龄++  名字+?
async function putData(item: jsonData){
  item.age ++
  item.name += "?"
  let res = await axios.put(url + item.id, item)
  console.log("修改", res.data)

}

// 删除数据
async function deleteData(item: jsonData){
  let res = await axios.delete(url + item.id)
  console.log("删除", res.data)
  getData()
}

// 获取详情
async function detailData(id: number){
  let res = await axios.get(url + id)
  console.log("详情", res.data)
}


getData()


</script>
axios.get(url, config)
axios.delete(url, config)
axios.post(url, data, config)
axios.put(url, data, config)
axios.patch(url, data, config)

data就是js里面的对象

config

{
  // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // 默认值

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
  // 你可以修改请求头。
  transformRequest: [function (data, headers) {
    // 对发送的 data 进行任意转换处理

    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对接收的 data 进行任意转换处理

    return data;
  }],

  // 自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是与请求一起发送的 URL 参数
  // 必须是一个简单对象或 URLSearchParams 对象
  params: {
    ID: 12345
  },

  // `paramsSerializer`是可选方法,主要用于序列化`params`
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function (params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求体被发送的数据
  // 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法
  // 在没有设置 `transformRequest` 时,则必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属: FormData, File, Blob
  // - Node 专属: Stream, Buffer
  data: {
    firstName: 'Fred'
  },
  
  // 发送请求体数据的可选语法
  // 请求方式 post
  // 只有 value 会被发送,key 则不会
  data: 'Country=Brasil&City=Belo Horizonte',

  // `timeout` 指定请求超时的毫秒数。
  // 如果请求时间超过 `timeout` 的值,则请求会被中断
  timeout: 1000, // 默认值是 `0` (永不超时)

  // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // default

  // `adapter` 允许自定义处理请求,这使测试更加容易。
  // 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
  adapter: function (config) {
    /* ... */
  },

  // `auth` HTTP Basic Auth
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` 表示浏览器将要响应的数据类型
  // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
  // 浏览器专属:'blob'
  responseType: 'json', // 默认值

  // `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
  // 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // 默认值

  // `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
  xsrfCookieName: 'XSRF-TOKEN', // 默认值

  // `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值

  // `onUploadProgress` 允许为上传处理进度事件
  // 浏览器专属
  onUploadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  // 浏览器专属
  onDownloadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
  maxContentLength: 2000,

  // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
  maxBodyLength: 2000,

  // `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
  // 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
  // 则promise 将会 resolved,否则是 rejected。
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认值
  },

  // `maxRedirects` 定义了在node.js中要遵循的最大重定向数。
  // 如果设置为0,则不会进行重定向
  maxRedirects: 5, // 默认值

  // `socketPath` 定义了在node.js中使用的UNIX套接字。
  // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。
  // 只能指定 `socketPath` 或 `proxy` 。
  // 若都指定,这使用 `socketPath` 。
  socketPath: null, // default

  // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
  // and https requests, respectively, in node.js. This allows options to be added like
  // `keepAlive` that are not enabled by default.
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // `proxy` 定义了代理服务器的主机名,端口和协议。
  // 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。
  // 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。
  // `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。
  // 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。
  // 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
  proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // see https://axios-http.com/zh/docs/cancellation
  cancelToken: new CancelToken(function (cancel) {
  }),

  // `decompress` indicates whether or not the response body should be decompressed 
  // automatically. If set to `true` will also remove the 'content-encoding' header 
  // from the responses objects of all decompressed responses
  // - Node only (XHR cannot turn off decompression)
  decompress: true // 默认值

}

常用的config

<script setup lang="ts">
import axios from "axios";

axios.get("/users", {
  baseURL: "http://localhost:3000", // 设置绝对地址
  transformRequest: [function (data, headers) {
    console.log("transformRequest", data, headers)
    return data
  }], // 可以在这里处理请求的数据
  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对接收的 data 进行任意转换处理
    // console.log("transformResponse", data)
    return JSON.parse(data);
  }],
  headers: {'Content-Type': 'application/json', "xxx": "xxx"},
  params: {
    xxx123: "xxx123"
  },
  timeout: 130, // 超时时间 单位毫秒  默认0 不超时
  auth: {
    username: 'root',
    password: 'root'
  },
  responseType: 'json', // 默认值
  
  
}).then(res => {
  console.log(res.data)
})


</script>

auth的编码规则

Basic base64encode(username:password)

axios实例

一般对接一个后端接口,上面的写法完全够用了

但是有些项目,前端需要对接几个后端接口,这个时候api接口地址完全不同,有时候响应也是五花八门

所以就需要创建一个实例,一个实例去对接一个api接口

<template>

</template>

<script setup lang="ts">
import axios from "axios";

const blogServerUrl = "http://localhost:3000"
const videoServerUrl = "http://localhost:3001"


const blogAxios = axios.create({
  baseURL: blogServerUrl,
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000,
})

const videoAxios = axios.create({
  baseURL: videoServerUrl,
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000
})

blogAxios.get("users").then(res => {
  console.log("博客服务", res.data)
})

videoAxios.get("users").then(res => {
  console.log("视频服务", res.data)
})


</script>

axios拦截器

这个算是axios中最有用的

在请求拦截器里面加用户认证

在响应拦截器里面判断后端错误,取数据

<template>

</template>

<script setup lang="ts">
import axios from "axios";

const blogAxios = axios.create({
  baseURL: "http://localhost:3000",
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000,
})

// 请求中间件
blogAxios.interceptors.request.use(function (config) {
  config.headers["token"] = "token123"
  return config
})
// 响应中间件
blogAxios.interceptors.response.use(function (response){
  if (response.status === 200){
    // 还可以再这里全局判断这个请求是不是正常的
    return  response.data
  }
  console.log(response.statusText)
  return Promise.reject(response.statusText);
}, function (error){
  // 超出 2xx 范围的状态码都会触发该函数。 一般是后端服务出错了
  // 对响应错误做点什么
  console.log(error)
  return Promise.reject(error);
})

blogAxios.get("users").then(res => {
  console.log("博客服务", res)
})


</script>

axios拦截器可以应用在axios主体上,还可以应用到axios实例上

如果是给主体加拦截器,实例是不会有的,反之亦然

axios默认值

全局 axios 默认值

axios.defaults.baseURL = "http://localhost:30001"
axios.defaults.headers["xxx"] = "xxx"
axios.defaults.headers.post["xxx1"] = "xxx1" // 只是post请求才有

实例默认值

// 创建实例时配置默认值
const instance = axios.create({
  baseURL: 'http://localhost:3000'
});

// 创建实例后修改默认值
instance.defaults.headers.common['Authorization'] = "xxx";

优先级

当前请求的配置 > 实例的默认值 > 全局默认值

错误处理

then模式

<script setup lang="ts">
import axios from "axios";

axios.get("http://localhost:30001/users").then(res => {
  console.log("博客服务", res)
}).catch(function (err) {
  console.log("出错了", err)
})
</script>

async模式

<script setup lang="ts">
import axios from "axios";
async function getData(){
  try {
    let res = await axios.get("http://localhost:3000/users")
    console.log("博客服务", res)
  }catch (err){
    console.log("出错了", err)
  }
}
getData()
</script>

文件上传

后端以go语言为例

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "path"
)

func Cors() gin.HandlerFunc {
  return func(context *gin.Context) {
    method := context.Request.Method

    context.Header("Access-Control-Allow-Origin", "*")
    context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
    context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
    context.Header("Access-Control-Expose-Headers", "*")
    context.Header("Access-Control-Allow-Credentials", "true")

    if method == "OPTIONS" {
      context.AbortWithStatus(http.StatusNoContent)
    }
  }
}

func upload(c *gin.Context) {
  fileHead, err := c.FormFile("file")
  if err != nil {
    c.JSON(200, gin.H{"code": 7, "msg": "参数错误"})
    return
  }
  savePath := path.Join("uploads", fileHead.Filename)
  err = c.SaveUploadedFile(fileHead, savePath)
  if err != nil {
    fmt.Println(err)
    c.JSON(200, gin.H{"code": 7, "msg": "上传失败"})
    return
  }
  c.JSON(200, gin.H{"code": 0, "data": savePath, "msg": "上传成功"})
}

func main() {
  router := gin.Default()
  router.Use(Cors()) // 跨域
  router.POST("upload", upload)
  router.Run(":8080")
}

使用axios进行文件上传,都是固定的写法

  1. 获取input标签中的file
  2. 构造FormData
  3. 发请求
<template>
  <div>
    <input type="file" name="file" id="upload" @change="upload">
  </div>
</template>

<script setup lang="ts">
import axios from "axios";

function upload(e: Event) {

  const target = e.target;
  if (target instanceof HTMLInputElement) {
    const files = target.files;
    if (files) {
      const formData = new FormData()
      for (let i = 0; i < files.length; i++) {
        formData.append('file', files[i])
      }
      axios.post("http://localhost:8080/upload", formData, {headers: {token: "xxx"}}).then(res => {
        console.log(res)
      })
    }
  }
}
</script>

上传进度

axios.post("http://localhost:8080/upload", formData, {
  headers: {token: "xxx"},
  onUploadProgress: (progressEvent: AxiosProgressEvent) => {
    const progress = Math.round((progressEvent.loaded / (progressEvent.total as number)) * 100)
    console.log('上传进度:' + progress + '%')
  }
}).then(res => {
  console.log(res)
})

取消上传

<template>
  <div>
    <input type="file" name="file" id="upload" @change="upload">
    <button @click="cancel">取消上传</button>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import type {Canceler, AxiosProgressEvent} from "axios";

const cancelToken = axios.CancelToken;
let cancelCtl : Canceler;

function upload(e: Event) {
  const target = e.target;
  if (target instanceof HTMLInputElement) {
    const files = target.files;
    if (files) {
      const formData = new FormData()
      for (let i = 0; i < files.length; i++) {
        formData.append('file', files[i])
      }
      axios.post("http://localhost:8080/upload", formData, {
        // 重新生成一个
        cancelToken: new cancelToken(function executor(c: Canceler) {
          cancelCtl = c
        }),
        headers: {token: "xxx"},
        onUploadProgress: (progressEvent: AxiosProgressEvent) => {
          const progress = Math.round((progressEvent.loaded / (progressEvent.total as number)) * 100)
          console.log('上传进度:' + progress + '%')
        }
      }).then(res => {
        console.log(res)
      })
    }
  }
}


function cancel() {
  cancelCtl('取消上传')
}

</script>

文件下载

后端以go语言为例

func download(c *gin.Context) {
  name := "厉害了.jpg"
  c.Header("Content-Type", "application/octet-stream")          // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
  c.Header("Content-Disposition", "attachment; filename="+name) // 用来指定下载下来的文件名,让浏览器认的
  c.Header("Content-Transfer-Encoding", "binary")               // 表示传输过程中的编码形
  filename := url.QueryEscape(name)
  c.Header("filename", filename) // 让前端认的
  c.File("uploads/5.jpg")
}

前端部分也是通用的

  1. 设置 responseType: 'blob'
  2. 构造blob
  3. 模拟a标签点击
  4. 移除a标签

function download() {
  axios.get("http://localhost:8080/download", {
    responseType: 'blob',
  }).then(res => {
    console.log(res.headers)
    if (res && res.status === 200) {
      const {data, headers} = res
      // 解析文件名
      let fileName = decodeURIComponent(headers["filename"])

      // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
      const blob = new Blob([data], {type: headers['Content-Type'] as string})

      // 创建a标签
      let dom = document.createElement('a')
      let url = window.URL.createObjectURL(blob)
      dom.href = url
      dom.download = decodeURI(fileName)
      dom.style.display = 'none'
      document.body.appendChild(dom)
      dom.click()
      // 删除a标签
      if (dom.parentNode) {
        (dom.parentNode as Node).removeChild(dom);
      }
      window.URL.revokeObjectURL(url);
    }
  })
}

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端

json-server

可能很多人并不会写后端,也可能没有一个可以用的后端接口地址

没关系,咱们自己造一个

json-server就是一个可以快速在json文件的基础上,起六个增删改改查查的六个接口

使用json-server先简单起一个服务

npm i -g json-server

db.json

{
  "users": [
    {
      "id": 1,
      "name": "枫枫",
      "age": 21,
      "addr": "湖南省长沙市"
    },
    {
      "id": 2,
      "name": "张三",
      "age": 22,
      "addr": "四川省成都市"
    }
  ]
}

运行服务

json-server -w db.json
# 增
POST  http://localhost:3000/users
{
    "name": "枫枫",
    "age": 22,
    "addr": "湖南省长沙市"
} 
## id自动增长
# 删
DELETE  http://localhost:3000/users/3
# 改  全字段更新,不传就删除
PUT  http://localhost:3000/users/3
{
    "name": "枫枫1",
    "age": 22
} 
# 改  单字段更新,传什么更什么
PATCH  http://localhost:3000/users/3
{
    "name": "枫枫2",
} 
# 查列表
GET  http://localhost:3000/users
# 查详情
GET  http://localhost:3000/users/1

axios使用

html模式

很多人可能也不会用vue的脚手架,没关系,会新建html就行了

<!doctype html>
<html lang="ch">
<head>
    <meta charset="UTF-8">
    <title>Axios使用</title>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<script>
    axios.get("http://localhost:3000/users").then(res => {
        console.log(res.data)
    })
</script>
</body>
</html>

打开控制台就能看到列表的json里面的数据了

后面的一些操作都是通用的

vue3项目中使用

npm init vue@latest

注意:本教程只是讲解axios,所以没勾vue-router和pinia

安装axois

npm i axios
<template>

</template>

<script setup lang="ts">
import axios from "axios";

axios.get("http://localhost:3000/users").then(res => {
  console.log(res.data)
})


</script>

axios增删改查

<template>
  <div>
    <table>
      <thead>
      <tr>
        <th>id</th>
        <th>用户名</th>
        <th>年龄</th>
        <th>地址</th>
        <th>操作</th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="item in data.list" :key="item.id">
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.age }}</td>
        <td>{{ item.addr }}</td>
        <td>
          <button @click="detailData(item.id as number)">详情</button>
          <button @click="putData(item)">修改</button>
          <button @click="deleteData(item)">删除</button>
        </td>
      </tr>
      </tbody>
    </table>
    <button @click="create">新增一条</button>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import {reactive} from "vue";
import type {AxiosResponse} from "axios";

const url: string = "http://localhost:3000/users/"

interface jsonData {
  readonly id?: number
  name: string
  age: number
  addr?: string
}

interface Data {
  list: jsonData[]
}

const data = reactive<Data>({
  list: []
})

// 请求列表
async function getData() {
  let res: AxiosResponse<jsonData[]> = await axios.get(url)
  data.list = res.data
}

// 增加数据
async function create() {
  let body: jsonData = {
    name: "王五",
    age: 23,
    addr: "北京市",
  }
  let res = await axios.post(url, body)
  console.log("新增", res.data)
  getData()
}

// 修改数据 年龄++  名字+?
async function putData(item: jsonData){
  item.age ++
  item.name += "?"
  let res = await axios.put(url + item.id, item)
  console.log("修改", res.data)

}

// 删除数据
async function deleteData(item: jsonData){
  let res = await axios.delete(url + item.id)
  console.log("删除", res.data)
  getData()
}

// 获取详情
async function detailData(id: number){
  let res = await axios.get(url + id)
  console.log("详情", res.data)
}


getData()


</script>
axios.get(url, config)
axios.delete(url, config)
axios.post(url, data, config)
axios.put(url, data, config)
axios.patch(url, data, config)

data就是js里面的对象

config

{
  // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // 默认值

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
  // 你可以修改请求头。
  transformRequest: [function (data, headers) {
    // 对发送的 data 进行任意转换处理

    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对接收的 data 进行任意转换处理

    return data;
  }],

  // 自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是与请求一起发送的 URL 参数
  // 必须是一个简单对象或 URLSearchParams 对象
  params: {
    ID: 12345
  },

  // `paramsSerializer`是可选方法,主要用于序列化`params`
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function (params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求体被发送的数据
  // 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法
  // 在没有设置 `transformRequest` 时,则必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属: FormData, File, Blob
  // - Node 专属: Stream, Buffer
  data: {
    firstName: 'Fred'
  },
  
  // 发送请求体数据的可选语法
  // 请求方式 post
  // 只有 value 会被发送,key 则不会
  data: 'Country=Brasil&City=Belo Horizonte',

  // `timeout` 指定请求超时的毫秒数。
  // 如果请求时间超过 `timeout` 的值,则请求会被中断
  timeout: 1000, // 默认值是 `0` (永不超时)

  // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // default

  // `adapter` 允许自定义处理请求,这使测试更加容易。
  // 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
  adapter: function (config) {
    /* ... */
  },

  // `auth` HTTP Basic Auth
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // `responseType` 表示浏览器将要响应的数据类型
  // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
  // 浏览器专属:'blob'
  responseType: 'json', // 默认值

  // `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
  // 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // 默认值

  // `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
  xsrfCookieName: 'XSRF-TOKEN', // 默认值

  // `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值

  // `onUploadProgress` 允许为上传处理进度事件
  // 浏览器专属
  onUploadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  // 浏览器专属
  onDownloadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
  maxContentLength: 2000,

  // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
  maxBodyLength: 2000,

  // `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
  // 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
  // 则promise 将会 resolved,否则是 rejected。
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认值
  },

  // `maxRedirects` 定义了在node.js中要遵循的最大重定向数。
  // 如果设置为0,则不会进行重定向
  maxRedirects: 5, // 默认值

  // `socketPath` 定义了在node.js中使用的UNIX套接字。
  // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。
  // 只能指定 `socketPath` 或 `proxy` 。
  // 若都指定,这使用 `socketPath` 。
  socketPath: null, // default

  // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
  // and https requests, respectively, in node.js. This allows options to be added like
  // `keepAlive` that are not enabled by default.
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // `proxy` 定义了代理服务器的主机名,端口和协议。
  // 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。
  // 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。
  // `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。
  // 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。
  // 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
  proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // see https://axios-http.com/zh/docs/cancellation
  cancelToken: new CancelToken(function (cancel) {
  }),

  // `decompress` indicates whether or not the response body should be decompressed 
  // automatically. If set to `true` will also remove the 'content-encoding' header 
  // from the responses objects of all decompressed responses
  // - Node only (XHR cannot turn off decompression)
  decompress: true // 默认值

}

常用的config

<script setup lang="ts">
import axios from "axios";

axios.get("/users", {
  baseURL: "http://localhost:3000", // 设置绝对地址
  transformRequest: [function (data, headers) {
    console.log("transformRequest", data, headers)
    return data
  }], // 可以在这里处理请求的数据
  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对接收的 data 进行任意转换处理
    // console.log("transformResponse", data)
    return JSON.parse(data);
  }],
  headers: {'Content-Type': 'application/json', "xxx": "xxx"},
  params: {
    xxx123: "xxx123"
  },
  timeout: 130, // 超时时间 单位毫秒  默认0 不超时
  auth: {
    username: 'root',
    password: 'root'
  },
  responseType: 'json', // 默认值
  
  
}).then(res => {
  console.log(res.data)
})


</script>

auth的编码规则

Basic base64encode(username:password)

axios实例

一般对接一个后端接口,上面的写法完全够用了

但是有些项目,前端需要对接几个后端接口,这个时候api接口地址完全不同,有时候响应也是五花八门

所以就需要创建一个实例,一个实例去对接一个api接口

<template>

</template>

<script setup lang="ts">
import axios from "axios";

const blogServerUrl = "http://localhost:3000"
const videoServerUrl = "http://localhost:3001"


const blogAxios = axios.create({
  baseURL: blogServerUrl,
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000,
})

const videoAxios = axios.create({
  baseURL: videoServerUrl,
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000
})

blogAxios.get("users").then(res => {
  console.log("博客服务", res.data)
})

videoAxios.get("users").then(res => {
  console.log("视频服务", res.data)
})


</script>

axios拦截器

这个算是axios中最有用的

在请求拦截器里面加用户认证

在响应拦截器里面判断后端错误,取数据

<template>

</template>

<script setup lang="ts">
import axios from "axios";

const blogAxios = axios.create({
  baseURL: "http://localhost:3000",
  headers: {
    "Content-Type": "application/json"
  },
  timeout: 1000,
})

// 请求中间件
blogAxios.interceptors.request.use(function (config) {
  config.headers["token"] = "token123"
  return config
})
// 响应中间件
blogAxios.interceptors.response.use(function (response){
  if (response.status === 200){
    // 还可以再这里全局判断这个请求是不是正常的
    return  response.data
  }
  console.log(response.statusText)
  return Promise.reject(response.statusText);
}, function (error){
  // 超出 2xx 范围的状态码都会触发该函数。 一般是后端服务出错了
  // 对响应错误做点什么
  console.log(error)
  return Promise.reject(error);
})

blogAxios.get("users").then(res => {
  console.log("博客服务", res)
})


</script>

axios拦截器可以应用在axios主体上,还可以应用到axios实例上

如果是给主体加拦截器,实例是不会有的,反之亦然

axios默认值

全局 axios 默认值

axios.defaults.baseURL = "http://localhost:30001"
axios.defaults.headers["xxx"] = "xxx"
axios.defaults.headers.post["xxx1"] = "xxx1" // 只是post请求才有

实例默认值

// 创建实例时配置默认值
const instance = axios.create({
  baseURL: 'http://localhost:3000'
});

// 创建实例后修改默认值
instance.defaults.headers.common['Authorization'] = "xxx";

优先级

当前请求的配置 > 实例的默认值 > 全局默认值

错误处理

then模式

<script setup lang="ts">
import axios from "axios";

axios.get("http://localhost:30001/users").then(res => {
  console.log("博客服务", res)
}).catch(function (err) {
  console.log("出错了", err)
})
</script>

async模式

<script setup lang="ts">
import axios from "axios";
async function getData(){
  try {
    let res = await axios.get("http://localhost:3000/users")
    console.log("博客服务", res)
  }catch (err){
    console.log("出错了", err)
  }
}
getData()
</script>

文件上传

后端以go语言为例

package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
  "net/http"
  "path"
)

func Cors() gin.HandlerFunc {
  return func(context *gin.Context) {
    method := context.Request.Method

    context.Header("Access-Control-Allow-Origin", "*")
    context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
    context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
    context.Header("Access-Control-Expose-Headers", "*")
    context.Header("Access-Control-Allow-Credentials", "true")

    if method == "OPTIONS" {
      context.AbortWithStatus(http.StatusNoContent)
    }
  }
}

func upload(c *gin.Context) {
  fileHead, err := c.FormFile("file")
  if err != nil {
    c.JSON(200, gin.H{"code": 7, "msg": "参数错误"})
    return
  }
  savePath := path.Join("uploads", fileHead.Filename)
  err = c.SaveUploadedFile(fileHead, savePath)
  if err != nil {
    fmt.Println(err)
    c.JSON(200, gin.H{"code": 7, "msg": "上传失败"})
    return
  }
  c.JSON(200, gin.H{"code": 0, "data": savePath, "msg": "上传成功"})
}

func main() {
  router := gin.Default()
  router.Use(Cors()) // 跨域
  router.POST("upload", upload)
  router.Run(":8080")
}

使用axios进行文件上传,都是固定的写法

  1. 获取input标签中的file
  2. 构造FormData
  3. 发请求
<template>
  <div>
    <input type="file" name="file" id="upload" @change="upload">
  </div>
</template>

<script setup lang="ts">
import axios from "axios";

function upload(e: Event) {

  const target = e.target;
  if (target instanceof HTMLInputElement) {
    const files = target.files;
    if (files) {
      const formData = new FormData()
      for (let i = 0; i < files.length; i++) {
        formData.append('file', files[i])
      }
      axios.post("http://localhost:8080/upload", formData, {headers: {token: "xxx"}}).then(res => {
        console.log(res)
      })
    }
  }
}
</script>

上传进度

axios.post("http://localhost:8080/upload", formData, {
  headers: {token: "xxx"},
  onUploadProgress: (progressEvent: AxiosProgressEvent) => {
    const progress = Math.round((progressEvent.loaded / (progressEvent.total as number)) * 100)
    console.log('上传进度:' + progress + '%')
  }
}).then(res => {
  console.log(res)
})

取消上传

<template>
  <div>
    <input type="file" name="file" id="upload" @change="upload">
    <button @click="cancel">取消上传</button>
  </div>
</template>

<script setup lang="ts">
import axios from "axios";
import type {Canceler, AxiosProgressEvent} from "axios";

const cancelToken = axios.CancelToken;
let cancelCtl : Canceler;

function upload(e: Event) {
  const target = e.target;
  if (target instanceof HTMLInputElement) {
    const files = target.files;
    if (files) {
      const formData = new FormData()
      for (let i = 0; i < files.length; i++) {
        formData.append('file', files[i])
      }
      axios.post("http://localhost:8080/upload", formData, {
        // 重新生成一个
        cancelToken: new cancelToken(function executor(c: Canceler) {
          cancelCtl = c
        }),
        headers: {token: "xxx"},
        onUploadProgress: (progressEvent: AxiosProgressEvent) => {
          const progress = Math.round((progressEvent.loaded / (progressEvent.total as number)) * 100)
          console.log('上传进度:' + progress + '%')
        }
      }).then(res => {
        console.log(res)
      })
    }
  }
}


function cancel() {
  cancelCtl('取消上传')
}

</script>

文件下载

后端以go语言为例

func download(c *gin.Context) {
  name := "厉害了.jpg"
  c.Header("Content-Type", "application/octet-stream")          // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
  c.Header("Content-Disposition", "attachment; filename="+name) // 用来指定下载下来的文件名,让浏览器认的
  c.Header("Content-Transfer-Encoding", "binary")               // 表示传输过程中的编码形
  filename := url.QueryEscape(name)
  c.Header("filename", filename) // 让前端认的
  c.File("uploads/5.jpg")
}

前端部分也是通用的

  1. 设置 responseType: 'blob'
  2. 构造blob
  3. 模拟a标签点击
  4. 移除a标签

function download() {
  axios.get("http://localhost:8080/download", {
    responseType: 'blob',
  }).then(res => {
    console.log(res.headers)
    if (res && res.status === 200) {
      const {data, headers} = res
      // 解析文件名
      let fileName = decodeURIComponent(headers["filename"])

      // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
      const blob = new Blob([data], {type: headers['Content-Type'] as string})

      // 创建a标签
      let dom = document.createElement('a')
      let url = window.URL.createObjectURL(blob)
      dom.href = url
      dom.download = decodeURI(fileName)
      dom.style.display = 'none'
      document.body.appendChild(dom)
      dom.click()
      // 删除a标签
      if (dom.parentNode) {
        (dom.parentNode as Node).removeChild(dom);
      }
      window.URL.revokeObjectURL(url);
    }
  })
}