Axios

Axios 是一个基于 Promise 的 HTTP 客户端,主要用于浏览器和 Node.js 中发送 HTTP 请求。它具有简洁的 API、拦截请求和响应、转化请求和响应数据等功能

功能

  • 支持 Promise API:可以使用 async/await 语法
  • 拦截请求和响应:能够在请求发送前或响应返回后进行处理
  • 自动将数据转换为 JSON 数据,也可以自定义转换方式
  • 可以取消正在进行的 HTTP 请求
  • 自动转换请求头:根据数据类型自动设置合适的 Content-Type
  • 客户端防止 XSRF:提供了 XSRF 保护机制

工程中的使用方式

  1. npm 安装
1
npm install axios
  1. 引入
1
2
3
4
5
// ES6 模块引入
import axios from "axios";

// CommonJS 引入
const axios = require("axios");
  1. 在 src 目录下新建一个 utils 目录,新建一个 request.js 文件,将代码添加到文件中,请根据自己的需求添加,这里是我在公司的 request.js 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// 导入依赖
import axios from "axios";
// 用于获取令牌
import { getToken, getRefreshToken } from "@/utils/auth";
// 调用Vuex中的登录/令牌相关方法
import store from "@/store";
// 用户交互提示
import { Message, MessageBox } from "element-ui";

// 创建Axios实例
const service = axios.create({
baseURL: window.config.base_api, // 基础 URL(从全局配置中获取,方便多环境切换)
withCredentials: true, // 跨域请求时携带 cookies
timeout: 300000, // 超时时间(300 秒,适合处理大文件上传/下载等耗时请求)
});

// 请求拦截器,在请求发送到服务器前,统一处理请求参数(如添加 Token、设置请求头)。为所有需要身份验证的请求自动添加 Token 到请求头,实现 “一次配置,全局生效”,无需在每个接口单独处理 Token。
service.interceptors.request.use(
(config) => {
// 获取token
const hasToken = getToken();
if (hasToken && config.url !== "/auth/oauth/token") {
// 如果有 Token,且请求的不是获取 Token 的接口(避免死循环),则添加到请求头
config.headers["Authorization"] = "Bearer " + hasToken;
}
return config;
},
(error) => {
// 请求发送失败时的处理
return Promise.reject(error);
}
);

// 响应拦截器,服务器返回响应后,统一处理响应数据(如解析数据、处理错误状态码)。
service.interceptors.response.use(
// 特殊处理:如果是二进制流(通常是文件下载),直接返回原始数据

(response) => {
const headers = response.headers;
if (headers["content-type"] === "application/octet-stream;charset=utf-8") {
return response.data;
}
// // 普通接口:直接返回响应体中的 data 字段(剥离 Axios 包装的额外信息)
const res = response.data;
return res;
// const status = response.status
// add by caozl 后期与接口对code编码 暂时不校验
// if the custom code is not 20000, it is judged as an error.
// if (res.code !== 20000) {
// Message({
// message: res.message || 'Error',
// type: 'error',
// duration: 5 * 1000
// })
// console.log(response, 'reponse')
// // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
// console.log(status, 'status === 401')
// if (status === 401) {
// // to re-login
// MessageBox.confirm('登录时间超时', 'Confirm logout', {
// confirmButtonText: '重新登陆',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// store.dispatch('user/resetToken').then(() => {
// location.reload()
// })
// })
// } else {
// return res
// }
},
// // 1. 根据 HTTP 状态码设置错误消息
async (err) => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = err.response.data.message;
break;
case 401:
err.message = err.response.data.msg || "登录认证失效";
break;
case 403:
err.message = "拒绝访问";
break;
case 404:
err.message = `请求地址出错: ${err.response.config.url}`;
break;
case 408:
err.message = "请求超时";
break;
case 426:
err.message = "用户名不存在或者密码错误";
break;
case 428:
err.message = "验证码错误";
break;
case 500:
err.message = err.response.data.message || err.response.data.msg;
break;
case 501:
err.message = "服务未实现";
break;
case 502:
err.message = err.response.data.message;
break;
case 503:
err.message = err.response.data.message;
break;
case 504:
err.message = "网关超时";
break;
case 505:
err.message = "HTTP版本不受支持";
break;
default:
}
}

// 1.判断请求超时
// if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {
// console.log('根据你设置的timeout/真的请求超时 判断请求现在超时了,你可以在这里加入超时的处理方案')
// return service.request(originalRequest);//例如再重复请求一次
// }
// 2.需要重定向到错误页面
// const errorInfo = error.response
// if (errorInfo) {
// // error =errorInfo.data//页面那边catch的时候就能拿到详细的错误信息,看最下边的Promise.reject
// if (errorInfo.status === 403) {
// router.push({
// path: '/error/403'
// })
// }

if (err.response.status === 401) {
if (err.response.data.code === 401) {
// token 请求401后 使用refreshToken 刷新一次token 如果还是有问题 在提示登录超时
const res = await store.dispatch(
"user/refreshToken",
getRefreshToken()
);
if (res) {
err.config.headers["Authorization"] = "Bearer " + getToken();
axios
.request(err.config)
.then((res) => {
return res;
})
.catch(() => {
MessageBox.confirm("登录认证失效", "登录认证失效", {
cancelButtonText: "取消",
confirmButtonText: "重新登陆",
type: "warning",
}).then(() => {
store.dispatch("user/resetToken").then(() => {
location.reload();
});
});
});
} else {
// to re-login
MessageBox.confirm("登录认证失效", "登录认证失效", {
cancelButtonText: "取消",
confirmButtonText: "重新登陆",
type: "warning",
}).then(() => {
store.dispatch("user/resetToken").then(() => {
location.reload();
});
});
}
} else {
Message({
message: err.message,
type: "error",
duration: 5 * 1000,
});
}
} else {
Message({
message: err.message,
type: "error",
duration: 5 * 1000,
});
}
return Promise.reject(err);
}
);

export default service;
  1. 在 src 目录下新建一个 api 文件夹,创建对应的功能的文件夹,新建 index.js 文件,里面用于配置并调用后端接口
1
2
3
4
5
6
7
8
9
10
import request from "@/utils/request";

// 新增挂号单
export function updateInsert(data) {
return request({
url: `/api/opc/RtpRegister/add`,
method: "post",
data: data,
});
}
  1. 在使用的文件下引入 undetaInsert 函数,并调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 引用
import { updateInsert, queryRegister } from '@/api/opc/doctorWorkStation/index'
// 调用
Addpatient(formdata) {
updateInsert(formdata).then(res => {
this.patientAddvisible = false
this.isCurrentPatient = false
this.currentPatient = {}
this.$store.dispatch('cashier/addRtpDiagnosisDTO', {})
this.msgSuccess('添加成功')
this.getList()
}).catch(error => {
if (error.response) {
if (error.response.data.code === 9999) {
this.$message.error(error.response.data.message)
this.patientAddvisible = false
}
}
})
}

Fetch

fetch 是浏览器内置的用于网络请求 API,用于替代传统的 XMLHttpRequest,基于 Promise 设计,返回 Promise 对象,支持 then()、catch()链式调用和 async/await,提供了更现代、更简洁的异步请求方式。它是 ES6+ 标准的一部分,目前已被所有现代浏览器支持。

基本用法

fetch(url,options):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 基本 GET 请求
fetch("https://api.example.com/data")
.then((response) => {
// 第一步:处理响应(解析为 JSON/文本/Blob 等)
return response.json(); // 解析为 JSON 对象
})
.then((data) => {
// 第二步:处理解析后的数据
console.log("请求结果:", data);
})
.catch((error) => {
// 捕获网络错误(如断网)
console.error("网络错误:", error);
});

工作流程:

  1. 调用 fetch():传入请求 URL 和配置选项,返回一个 Promise 对象
  2. fetch 返回的 Promise 成功状态对应的是 Respose 对象,需要通过它的方法解析数据,解析后返回一个 Promise,通过 then()获取数据
  • response.json():解析为 JSON 数据
  • response.text():解析文文本
  • response.blob():解析为二进制 Blob
  • response.formData():解析为 FormData 表单数据
  • respones.arrayBuffer():解析为二进制数组(处理二进制数据)
  1. 用 then()获取数据后对数据进行处理

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fetch("https://api.example.com/users", {
method: "POST", // 请求方法:GET(默认)、POST、PUT、DELETE 等
headers: {
// 请求头
"Content-Type": "application/json",
Authorization: "Bearer token123",
},
body: JSON.stringify({ name: "John", age: 30 }), // 请求体(POST/PUT 等方法需要)
mode: "cors", // 跨域模式:cors(默认)、no-cors、same-origin
credentials: "include", // 是否携带 Cookie:include(携带)、same-origin(同域携带)、omit(不携带)
cache: "no-cache", // 缓存策略:default、no-store、reload、no-cache 等
timeout: 5000, // 超时时间(部分浏览器支持,建议通过 AbortController 实现)
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));

使用 async/await 简化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");

// 处理 HTTP 错误
if (!response.ok) {
throw new Error(`状态码: ${response.status}`);
}

const data = await response.json(); // 解析 JSON
console.log("数据:", data);
return data;
} catch (error) {
console.error("请求失败:", error.message);
}
}

fetchData();