# Axios 用法及配置
# 1. 常用配置项
# 1. 发起 GET 请求
// Make a request for a user with a given ID | |
axios.get('/user?ID=12345') | |
.then(response=> { | |
console.log(response); | |
}) | |
.catch(error=> { | |
console.log(error); | |
}); | |
// Optionally the request above could also be done as | |
axios.get('/user', { | |
params: { | |
ID: 12345 | |
} | |
}) | |
.then(response => { | |
console.log(response); | |
}) | |
.catch(error=> { | |
console.log(error); | |
}); |
# 2. 发起 POST 请求
axios.post('/user', { | |
firstName: 'Fred', | |
lastName: 'Flintstone' | |
}) | |
.then(response=> { | |
console.log(response); | |
}) | |
.catch(error=> { | |
console.log(error); | |
}); |
# 3. 同时发起多个请求
function getUserAccount() { | |
return axios.get('/user/12345'); | |
} | |
function getUserPermissions() { | |
return axios.get('/user/12345/permissions'); | |
} | |
axios.all([getUserAccount(), getUserPermissions()]) | |
.then(axios.spread((acct, perms)=> { | |
// Both requests are now complete | |
})); |
# 2.axios api (可以通过导入相关配置发起请求)
# 1.axios(config)
// 发起一个 POST 请求 | |
axios({ | |
method: 'post', | |
url: '/user/12345', | |
data: { | |
firstName: 'Fred', | |
lastName: 'Flintstone' | |
} | |
}); | |
// 获取远程图片 | |
axios({ | |
method: 'get', | |
url: 'http://bit.ly/2mTM3ny', | |
responseType: 'stream' | |
}).then( response=>{ | |
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) | |
}) |
# 2.axios(url[,config])
// 发起一个 GET 请求 (GET 是默认的请求方法) | |
axios('/user/111'); |
请求方法别名: axios 为所有支持的请求方法均提供了别名
使用以下别名方法时,url, method 和 data 等属性不用在 config 重复声明
- axios.request(config)
- axios.get(url[,config])
- axios.delete(url[,config])
- axios.head(url[,config])
- axios.options(url[,config])
- axios.post(url,data[,config])
- axios.put(url[,data[,config]])
- axios.patch(url[,data[,config]])
同时发生的请求
- axios.all(iterable)
- axios.sperad(callback)
# 3. 创建 axios 实例
# 1. 创建拥有通用配置的 axios 实例
axios.create([config])
var instance = axios.create({ | |
baseURL: 'http://some-domain.com/api', | |
timeout: 1000, | |
headers: {'X-Custom-Header': 'foobar'} | |
}) |
实例的方法
- axios#request(config)
- axios#get(url[, config])
- axios#delete(url[, config])
- axios#head(url[, config])
- axios#options(url[, config])
- axios#post(url[, data[, config]])
- axios#put(url[, data[, config]])
- axios#patch(url[, data[, config]])
请求配置
以下是所有可用的请求配置项,只有 url 是必填,如果没有指定请求方式,默认请求方法是 GET
{ | |
// `url` 是请求接口地址 | |
url: '/Info', | |
// `method` 是请求方法 默认值: GET | |
method: 'get', | |
// 如果 URL 不是绝对路径,那么将 baseURL 和 url 拼接作为请求的接口地址 | |
// 用来区分不同环境 | |
baseURL: 'http://some-domain.com/api/', | |
// 用于请求之前对请求数据进行操作 | |
// 请求方法为 `PUT`, `POST` 和 `PATCH` 时可用 | |
// 最后一个函数需 return 出相应数据 | |
// 可以修改 headers | |
transformRequest: [(data, headers)=>{ | |
// 对 data 进行一些操作 | |
return data | |
}], | |
// `headers` are custom headers to be sent | |
headers: {'X-Requested-With': 'XMLHttpRequest'}, | |
// URL 参数 | |
// 必须是一个纯对象或者 URL 参数对象 | |
params: { | |
ID: 10010 | |
}, | |
// 负责序列化 `params` 的可选函数 | |
paramsSerializer: params=>{ | |
return Qs.stringify(params,{arrayFormat: 'brackets'}) | |
} | |
// 请求体数据 | |
// 请求方法为 `PUT`, `POST` 和 `PATCH` 时可用 | |
// 当没有设置 `transformRequest` 时,必须是一下几种格式 | |
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams | |
// - Browser only: FormData, File, Blob | |
// - Node only: Stream, Buffer | |
data: { | |
firstName: 'Fred' | |
}, | |
// 请求超时时间 (毫秒) | |
timeout: 1000, | |
// 是否携带 cookie 信息 默认值:false | |
withCredentials: false, | |
// 统一处理 request 让测试更加容易 | |
// 返回一个 promise 并提供一个可用的 response | |
adapter: config =>{ | |
/*...*/ | |
}, | |
// `auth` indicates that HTTP Basic auth should be used, and supplies credentials. | |
// This will set an `Authorization` header, overwriting any existing | |
// `Authorization` custom headers you have set using `headers`. | |
auth: { | |
username: 'janedoe', | |
password: 's00pers3cret' | |
}, | |
// 响应格式 默认值: json | |
// 可选项 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' | |
responseType: 'json', | |
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token | |
xsrfCookieName: 'XSRF-TOKEN', // default | |
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value | |
xsrfHeaderName: 'X-XSRF-TOKEN', // default | |
// 处理上传进度事件 | |
onUploadProgress: progressEvent=> { | |
// Do whatever you want with the native progress event | |
}, | |
// 处理下载进度事件 | |
onDownloadProgress: function (progressEvent) { | |
// Do whatever you want with the native progress event | |
}, | |
// 设置 http 响应内容的最大长度 | |
maxContentLength: 2000, | |
// 定义可获得的 http 响应状态码 | |
//return true, 设置为 null 或者 undefined, promise 将 resolved, 否则将 rejected | |
validateStatus: status =>{ | |
return status >= 200 && status < 300 // default | |
}, | |
// 最大重定向次数 | |
maxRedirects: 5, // 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' defines the hostname and port of the proxy server | |
// Use `false` to disable proxies, ignoring environment variables. | |
// `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and | |
// supplies credentials. | |
// This will set an `Proxy-Authorization` header, overwriting any existing | |
// `Proxy-Authorization` custom headers you have set using `headers`. | |
// 代理 | |
proxy: { | |
host: '127.0.0.1', | |
port: 9000, | |
auth: { | |
username: 'mikeymike', | |
password: 'rapunz3l' | |
} | |
}, | |
// `cancelToken` specifies a cancel token that can be used to cancel the request | |
// (see Cancellation section below for details) | |
// 用于取消请求 | |
cancelToken: new CancelToken(cancel=>{...}) | |
} |
# 2. 取消重复的请求
- 利用
CancelToken
工厂函数创建 cancel token
const CancelToken = axios.CancelToken | |
const source = CancelToken.source() | |
//get 方法使用案例 | |
axios.get('user/111',{ | |
cancelToken: source.token | |
}).catch(thrown => { | |
if(axios.isCancel(thrown)){ | |
console.log('Request canceled', thrown.message) | |
} else { | |
// TODO: handle error | |
} | |
}) | |
//post 使用案例 | |
axios.post('/user/111',{ | |
name: 'name ' | |
},{ | |
cancelToken: source.token | |
}) | |
// 执行取消请求操作 | |
source.cancel('请求已取消') |
- 传递 executor 函数到 CancelToken 的构造函数来创建 cancel token
- 不同请求可以定义同一个取消请求的方法名,来批量取消多个请求
const CancelToken = axios.CancelToken | |
let cancel | |
axios.get('/user/111',{ | |
cancelToken: new CancelToken(function executor(c) { | |
cancel = c | |
}) | |
}) | |
// 执行取消请求操作 | |
cancel() |
# 3. 响应数据组成 response
- response 由一下部分信息组成
{ | |
// 服务端返回的状态码 | |
status: 200, | |
// 服务端返回数据 | |
data: {}, | |
// 服务端返回的状态信息 | |
statusText: 'OK', | |
// 响应头:响应头名称都是小写 | |
headers: {}, | |
//axios 请求配置 | |
config: {}, | |
// 请求 | |
request: {} | |
} |
- 用 then 接收响应信息
axios.get('/user/111') | |
.then(response=>{ | |
console.log(response.status) | |
console.log(response.data) | |
console.log(response.statusText) | |
console.log(response.headers) | |
console.log(response.config) | |
}) |
# 4. 默认配置
全局修改 axios 默认配置
axios.default.baseURL = 'https://api.example.com'; | |
axios.default.headers.common['Authorization'] = AUTH_TOKEN; | |
axios.default.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; |
实例默认配置
// 创建实例时修改配置 | |
var instance = axios.create({ | |
baseURL: 'https:/api.example.com' | |
}) | |
// 实例创建之后修改配置 | |
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN; |
配置优先级
配置项通过一定的规则合并,request config > instance.defaults > 系统默认,优先低的被覆盖
// 创建一个实例,超时时间为系统默认的 0 | |
var instance = axios.create(); | |
// 通过 instance.defaults 重新设置超时时间为 2.25s, 优先级比系统默认高 | |
instance.defaults.timeout = 2500; | |
// 通过 request config 重新设置超时时间为 5s, 因为优先级比 instance.defaults 和系统默认都高 | |
instance.get('/longRequest',{ | |
timeout: 5000 | |
}) |
# 5. 拦截器
- 在 then 和 catch 之前拦截请求和响应
// 添加一个请求拦截器 | |
axios.interceptors.request.use(config =>{ | |
// 在发送请求前执行一些操作 | |
return config | |
},error=>{ | |
// 处理请求错误 | |
return Promise.reject(error) | |
}) | |
// 添加一个响应拦截器 | |
axios.interceptors.response.use(response=> { | |
// 处理响应数据 | |
return response | |
}, error=> { | |
// 处理响应错误 | |
return Promise.reject(error) | |
}) |
- 移除拦截器
// 创建一个请求拦截器 | |
var myInterceptor = axios.interceptors.request.use(()=>{/*...*/}) | |
// 移除拦截器 | |
axios.interceptors.request.eject(myInterceptor) |
- 为 axios 实例添加一个拦截器
var instance = axios.create() | |
instance.interceptors.request.use(()=>{/*...*/}) |
- 错误处理
axios.get('/user/111') | |
.catch(error=> { | |
if (error.response) { | |
// 发送请求后,服务端返回响应码不是 2xx | |
console.log(error.response.data) | |
console.log(error.response.status) | |
console.log(error.response.headers) | |
} else if (error.request) { | |
// 发送请求但是没有响应返回 | |
console.log(error.request) | |
} else { | |
// 未知错误 | |
console.log('Error',error.message) | |
} | |
console.log(error.config) | |
}) |
# 4.axios 无感知刷新 token
import axios from "axios"; // 引入 axios | |
import qs from "qs";// 序列化 post 接口请求参数 | |
import LocalStorage from "./localStorage.js"; //H5 本地存储封装方法 | |
let SECURITY_URL = "http://192.168.1.17:5505/security-amass/";// 刷新 token 接口的 base 路径 | |
axios.defaults.headers.post["Content-Type"] ="application/x-www-form-urlencoded;charset=UTF-8"; | |
axios.defaults.headers.post["Access-Control-Allow-Origin"] = "*"; | |
axios.defaults.withCredentials = false; // 携带 cookie | |
// 创建一个 axios 实例 | |
const instance = axios.create({ | |
timeout: 300000, | |
}); | |
// 是否正在请求刷新 token 接口的标记 | |
let isRefreshing = false; | |
// 请求队列 | |
let requests = []; | |
// 刷新 token 方法 | |
function refreshToken(params) { | |
return instance.get(SECURITY_URL + "oauth/token", params); | |
} | |
// 请求结果拦截器 | |
instance.interceptors.response.use( | |
(response) => { | |
// 接下来会在这里进行 token 过期的逻辑处理 | |
const config = response.config; | |
let code = response.data.code; | |
// 这里的 code 值是跟后端约定好的, 40009 代表 token 已经过期 | |
if (code == "40009") { | |
if (!isRefreshing) { | |
isRefreshing = true; | |
let refresh_token = LocalStorage.get("refresh_token"); | |
// 这里是我的项目中刷新 token 要传的参数,具体都传那些参数需要与后端开发确认 | |
let loginData = { | |
grant_type: "refresh_token", | |
client_id: "impawning", | |
client_secret: "impawning", | |
refresh_token, | |
}; | |
refreshToken({ params: loginData }) | |
.then((res) => { | |
let access_token = res.data.access_token; | |
let refresh_token = res.data.refresh_token; | |
LocalStorage.set("access_token", res.data.access_token); | |
LocalStorage.set("refresh_token", res.data.refresh_token); | |
config.headers["access_token"] = access_token; | |
config.headers["refresh_token"] = refresh_token; | |
requests.forEach((cb) => cb(access_token, refresh_token)); | |
requests = []; | |
return instance(config); | |
}) | |
.catch((err) => { | |
window.location.href = "/"; | |
}) | |
.finally(() => { | |
isRefreshing = false; | |
}); | |
} else { | |
// 正在刷新 token,返回一个未执行 resolve 的 promise | |
return new Promise((resolve) => { | |
// 将 resolve 放进队列,用一个函数形式来保存,等 token 刷新后直接执行 | |
requests.push((access_token, refresh_token) => { | |
config.headers["access_token"] = access_token; | |
config.headers["refresh_token"] = refresh_token; | |
resolve(instance(config)); | |
}); | |
}); | |
} | |
} else if (code == "40005" || code == "40003") {// 这里代表 token 失效和 token 错误 | |
window.location.href = "/"; | |
} else { | |
return response; | |
} | |
}, | |
(error) => { | |
return Promise.reject(error); | |
} | |
); | |
const api = { | |
get(url, data) { | |
instance.defaults.headers.common["access_token"] = LocalStorage.get( | |
"access_token" | |
); | |
instance.defaults.headers.common["refresh_token"] = LocalStorage.get( | |
"refresh_token" | |
); | |
return instance.get(url, { params: data }); | |
}, | |
post(url, data) { | |
instance.defaults.headers.common["access_token"] = LocalStorage.get( | |
"access_token" | |
); | |
instance.defaults.headers.common["refresh_token"] = LocalStorage.get( | |
"refresh_token" | |
); | |
//post 接口封装 | |
return instance.post(url, qs.stringify(data)); | |
}, | |
}; | |
export { api }; |