文章目录
- 前言
- 一、认识axios
- 1、axios是什么?
- 2、为什么要用axios?
- 特性
- 二、封装axios
- 1.引入库
- 2.建立封装axios实例文件
- 3.导入所需依赖
- 4.创建axios实例
- 5.axios拦截器
- 请求拦截器
- 响应拦截器
- 5.封装成请求
- 6.完整代码
- 代码
- 代码中的setLocalStorage和getLocalStorage方法
- setLocalStorage
- getLocalStorage
- 总结
前言
在前端的高速发展下,单页面应用大多采用前后端分离的开发思路,现在帮助前后端交互的工具数不胜数,axios无疑是当今最受欢迎的http库,但是你真的玩透了axios吗?接下来,我们将一起进行一次axios的封装体验,做出属于自己的axios。(本次封装演示建立Vue项目中)
一、认识axios
此环节带领大家了解axios,如果熟练的同学可直接移步到下面的封装环节哦!
1、axios是什么?
官方解释:
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
2、为什么要用axios?
axios最大的亮点就是它支持了ES6里的 Promise Api,感兴趣的同学可以去看一看阮一峰写的 《ES6入门教程》,传送门:ES6入门教程
特性
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
废话不多说,我们直接开始!
二、封装axios
1.引入库
使用npm
$ npm install axios
使用yarn
$ yarn add axios
使用bower
$ bower install axios
2.建立封装axios实例文件
因为项目一般都是工程化,所以我们得建立一个文件来单独封装axios,这样才能更加清晰。
通常我们在项目src目录下新建utils文件夹,然后在其中新建 request.js文件,这个文件是主要书写axios的封装过程。
3.导入所需依赖
// 导入axios
import axios from 'axios'
// 导入element的message组件
import { Message } from 'element-ui'
// 导入其他文件里的localStorage方法(操作token时用到,后面将给出详细代码)
import { setLocalStorage,getLocalStorage } from '@/utils/utils'
4.创建axios实例
首先,我们根据文档提供的create方法新建一个axios实例
const instance = axios.create({
// baseURL 将自动加在 url`前面,除非 url 是一个绝对 URL。
// 它可以通过设置一个 baseURL 便于为 axios 实例的方法传递相对 URL
baseURL: baseUrl,
// timeout设置一个请求超时时间,如果请求时间超过了timeout,请求将被中断,单位为毫秒(ms)
timeout: 60000,
// headers是被发送的自定义请求头,请求头内容需要根据后端要求去设置,这里我们使用本项目请求头。
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
如果你想使用原生的axios并且设置全局的axios的时候。你也可以用以下这种方法进行配置,比如:
// 这里设置了axios的全局baseURL地址,其他也可类似这样进行设置
axios.defaults.baseURL = 'https://api.example.com';
5.axios拦截器
为什么需要拦截器呢?
- 当你在发起request请求前想做一些事时,比如携带token,或者处理请求错误。
- 当你在接受response前想做一些事时,比如处理错误码,数据过滤。
请求拦截器
// http request 请求拦截器
instance.interceptors.request.use(
config => {
// 这里判断localStorage里面是否存在token,如果有则在请求头里面设置
if (localStorage.jwtToken) {
config.headers.Authorization = getLocalStorage("jwtToken");
}
return config
},
err => {
return Promise.reject(err)
}
)
vscode的提示告诉我config是个这个东西
相信大家和我一样对config具体是个什么东西有点好奇,话不多说,让我们打印看看它是什么妖魔鬼怪吧。
可以看出,这就是我们用axios封装的请求配置,里面有我们之前设置的baseURL,有headers和timeout等参数。
响应拦截器
// http response 响应拦截器
instance.interceptors.response.use(
response => {
// 这里对响应的数据做了操作,大家可以自己设置响应过滤哦,下面会给出具体代码
return handleData(response.data)
},
error => {
// 错误信息需要和后端进行协调,然后去配合设置啦
if(error.response.data.status === 500 && (error.response.data.message === 'token out time'||error.response.data.message==='登录失败或未登录')){
// 调用登出api
logonApi.signOut();
// 存放token到localStorage,这里因为登出,所以设置为空
setLocalStorage('jwtToken');
// 跳回登录页
window.location.href = baseUrl.url1;
}
let err = error.response.data.message;
if (err != '' && err != null && err != undefined) {
// 错误提醒
Message({
type: 'error',
message: error.response.data.message
})
return Promise.reject(error.response.data)
} else {
Message({
type: 'error',
message: 'HTTP:服务器遇到错误,无法完成请求。'
})
}
})
很显然,从vscode是看不出它是个啥东西了,让我们看看它是什么妖魔鬼怪!
有没有发现,它除了包含我们之前的request配置,还多了一个返回的数据。所以我们可以根据它返回的数据来完成自己想要的操作啦。
5.封装成请求
const postFn = (url, data) => {
return instance
.post(url, data)
.catch(handleError)
}
instance是我们之前封装好的axios实例,我们可以通过它调用axios实例方法完成封装。
6.完整代码
由于代码中很多设置是项目要求,所以仅供参考!
代码
import axios from 'axios'
import { baseUrl, pathUrl } from './env'
import Qs from 'qs'
import { Message } from 'element-ui'
import { setLocalStorage,getLocalStorage } from '@/utils/utils'
import logonApi from '../api/logon'
const instance = axios.create({
// baseURL: baseUrl,
timeout: 60000,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
// http request 请求拦截器
instance.interceptors.request.use(
config => {
config.headers.AcceptLanguage = getLocalStorage("locale");
if (localStorage.jwtToken) {
config.headers.Authorization = getLocalStorage("jwtToken");
}
console.log('config',config);
return config
},
err => {
return Promise.reject(err)
}
)
// http response 响应拦截器
instance.interceptors.response.use(
response => {
console.log('response',response);
return handleData(response.data)
},
error => {
if(error.response.data.status===500&&(error.response.data.message==='token out time'||error.response.data.message==='登录失败或未登录')){
logonApi.signOut();
// window.location.href = baseUrl.url1;
setLocalStorage('jwtToken');
window.location.href = baseUrl.url1;
}
let err = error.response.data.message;
if (err != '' && err != null && err != undefined) {
Message({
type: 'error',
message: error.response.data.message
})
return Promise.reject(error.response.data)
} else {
Message({
type: 'error',
message: 'HTTP:服务器遇到错误,无法完成请求。'
})
}
})
// 生成新的url
function generateUrl (url) {
const domain = url.domain ? baseUrl[url.domain] : baseUrl['url1'];
const path = url.path ? pathUrl[url.path] : pathUrl['url1'];
const newurl = Object.prototype.toString.call(url) === '[object Object]' ? url.url : url;
return domain + path + newurl
}
// 二次封装方法
const getFn = (url, data) => {
let newurl = generateUrl(url);
if (data) {
newurl += '?'
for (let i in data) {
if (data[i] !== '' && data[i] !== null) {
newurl += i + '=' + data[i] + '&'
}
}
newurl = newurl.toString().substring(0, newurl.length - 1)
}
return instance
.get(newurl)
.catch(handleError)
}
const postFn = (url, data) => {
return instance
.post(generateUrl(url), data)
.catch(handleError)
}
const deleteFn = (url, data) => {
return instance
.delete(generateUrl(url), data)
.catch(handleError)
}
const postJSON = (url, data) => {
data = Qs.stringify(data);
return instance
.post(generateUrl(url), data)
.catch(handleError)
}
const patchFn = (url, data) => {
return instance
.patch(generateUrl(url), data)
.catch(handleError)
}
const postFile = (url, data, config) => {
return instance
.post(generateUrl(url), data, config)
.catch(handleError)
}
// 捕获请求错误
function handleError (error) {
// Promise.reject(error)
return error
}
// 处理数据
function handleData (data) {
if (data.hasOwnProperty('ret')) {
if (data.ret!==null&&data.ret.hasOwnProperty('token')) {
setLocalStorage('jwtToken',data.ret.token);
}
}
if (data.errcode !== 0){
Message({
type: 'error',
message: data.errmsg
})
}
if(data.errcode === 200 && data.errmsg === "权限鉴定失败"){
setLocalStorage('jwtToken');
window.location.href = baseUrl.url1;
}
if(data.errcode === 300){ // token超时后 前端处理
setLocalStorage('jwtToken');
window.location.href = baseUrl.url1;
}
return data
}
export default {
postFile: postFile,
postJSON: postJSON,
post: postFn,
get: getFn,
delete: deleteFn,
patch: patchFn
}
代码中的setLocalStorage和getLocalStorage方法
setLocalStorage
// 设置LocalStorage过期
const setLocalStorage = function (key, value, days) {
value = JSON.stringify(value);
// 设置过期原则
if (!value) {
localStorage.removeItem(key)
} else {
var Days = days || 24; // 以小时为单位,默认24小时
var exp = new Date();
localStorage[key] = JSON.stringify({
value,
// 和后端协商做了失效时间
expires: exp.getTime() + Days * 1000*60*60
})
}
}
getLocalStorage
const getLocalStorage = function (name) {
try {
let o = JSON.parse(localStorage[name]);
if (!o || o.expires < Date.now()) {
return ''
} else {
return JSON.parse(o.value)
}
} catch (e) {
// 兼容其他localstorage
return localStorage[name]
}
}
总结
封装其实是非常简单的,希望大家都能去手写一遍,这样在以后的项目中就能得心应手的使用啦!