axios

1.axios的基础使用

GET:获取
POST:添加
PUT:更新
DELETE:删除

// 引入bootstrap css样式
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.0.2/css/bootstrap.min.css" rel="stylesheet">
// 引入axios 
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
const btns=document.querySelectorAll('button');
//第一个 获取id为2的数据
btns[0].onclick=function(){
    // 发送ajax请求
    axios({
        // 请求类型
        method:'GET/POST/DELETE/PUT',
        // URL
        url:'http://localhost:3000/posts/2',
    }).then(response=>{
        console.log(response);
    }) 
}

2.axios拦截器设定

1.默认配置

  axios.defaults.method='GET', // 设置默认的请求类型
 axios.defaults.baseURL='http://localhost:3000', // 设置基础的url
 axios.defaults.params={id:1}, // 默认参数
 axios.defaults.timeout=3000;// 响应超时

2.创建实例对象

const axiosSelf = axios.create({
	baseURL:'http://localhost:3000',
	timeout:3000
})

3.设置请求拦截器 (可对请求参数进行设置 )

 axiosSelf.interceptors.request.use(function(config){
   console.log("请求成功");
   // 设置 config 请求参数
   config.params={a:100};
   config.timeout=3000;
   return config
   // throw '参数出了问题';
},function(error){
   console.log("请求失败");
   return Promise.reject(error);
})

4.设置响应拦截器

axiosSelf.interceptors.response.use(function(config){
  console.log("响应拦截器成功",config);
    return config.data; // 直接返回响应体
    //   return config
},function(error){
    console.log("响应拦截器失败",error);
    return Promise.reject(error)
})

5.请求接口

 axiosSelf({
  url:'/comments'
}).then(response=>{
    console.log("自定义",response);
}).catch(reason=>{
    console.log('自定义回调失败');
})

3.axios 的请求取消

前提:接口要有响应时间(几秒后再请求)如
json-server --watch db.json -d 2000 使接口2s后请求以看到效果

1.取消请求内容

   // 2.声明全局变量
let cancel = null;
btns[0].onclick=function(){
  axios.request({
      method:'GET',
      url:'http://localhost:3000/posts',
      // 1.  添加配置对象属性
      cancelToken:new axios.CancelToken(function(c){
         // 3.将 c 值赋值给 cancel
         cancel = c;
      })
  }).then(response=>{
     console.log(response);
  })
}

//绑定第二个请求--取消请求
btns[1].onclick=function(){
   cancel();
}

2 取消请求结果图片

在这里插入图片描述

3. 应用于一个接口被多次点击调用后只调用一次(防止接口多次请求)----接口防抖

let cancel = null;
btns[0].onclick=function(){
  // 当一个接口被多次点击请求后,为了防止接口多次请求
   if(cancel !== null){
      cancel();
   }
  // 借助request
  axios.request({
      method:'GET',
      url:'http://localhost:3000/posts',
      // 1.  添加配置对象属性
      cancelToken:new axios.CancelToken(function(c){
         // 3.将 c 值赋值给 cancel
         cancel = c;
      })
  }).then(response=>{
     console.log(response);
     cancel = null ;
  })
 }

  //绑定第二个请求--取消请求
  btns[1].onclick=function(){
      cancel();
  }

结果图片

在这里插入图片描述

axios 接口的封装

  • 封装
// 统一的请求发送
import axios from 'axios'
import { message, Modal, notification } from 'ant-design-vue'
import sysConfig from '@/config/index'
import tool from '@/utils/tool'
import qs from 'qs'
import { viewTagsStore } from '@/store'

// 以下这些code需要重新登录
const reloadCodes = [401, 1011007, 1011008]
const errorCodeMap = {
	400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
	401: '用户没有权限(令牌、用户名、密码错误)。',
	403: '用户得到授权,但是访问是被禁止的。',
	404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
	406: '请求的格式不可得。',
	410: '请求的资源被永久删除,且不会再得到的。',
	422: '当创建一个对象时,发生一个验证错误。',
	500: '服务器发生错误,请检查服务器。',
	502: '网关错误。',
	503: '服务不可用,服务器暂时过载或维护。',
	504: '网关超时。'
}
// 定义一个重新登录弹出窗的变量
const loginBack = ref(false)
// 创建 axios 实例
const service = axios.create({
	baseURL: '/api', // api base_url
	timeout: sysConfig.TIMEOUT // 请求超时时间
})
// token 键定义
const accessTokenKey = sysConfig.ACCESS_TOEKN_KEY
const refreshAccessTokenKey = sysConfig.REFRESH_TOEKN_KEY
// 清除 token
const clearAccessTokens = () => {
	tool.data.remove(accessTokenKey)
	tool.data.remove(refreshAccessTokenKey)
}
// HTTP request 拦截器
service.interceptors.request.use(
	(config) => {
		const token = tool.data.get(accessTokenKey)
		if (token) {
			config.headers[sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + token
			// 判断 accessToken 是否过期
			const jwt = decryptJWT(token)
			const exp = getJWTDate(jwt.exp)
			// token 已经过期
			if (new Date() >= exp) {
				// 获取刷新 token
				const refreshAccessToken = tool.data.get(refreshAccessTokenKey)
				// 携带刷新 token
				if (refreshAccessToken) {
					config.headers['X-' + sysConfig.TOKEN_NAME] = sysConfig.TOKEN_PREFIX + refreshAccessToken
				}
			}
		}
		if (!sysConfig.REQUEST_CACHE && config.method === 'get') {
			config.params = config.params || {}
			config.params._ = new Date().getTime()
		}
		Object.assign(config.headers, sysConfig.HEADERS)
		return config
	},
	(error) => {
		return Promise.reject(error)
	}
)

// 保持重新登录Modal的唯一性
const error = () => {
	loginBack.value = true
	Modal.error({
		title: '提示:',
		okText: '重新登录',
		content: '登录已失效, 请重新登录',
		onOk: () => {
			const store = viewTagsStore() //获取viewTagsStore
			console.log(store.viewTags)

			const lastPath = store.lastPath //获取最后一个路由
			//如果有lastPath
			if (lastPath !== '') {
				localStorage.setItem('lastVisitPath', lastPath) //记录当前路由
			}
			loginBack.value = false
			tool.data.remove(accessTokenKey)
			tool.data.remove(refreshAccessTokenKey)
			tool.data.remove('USER_INFO')
			tool.data.remove('MENU')
			tool.data.remove('PERMISSIONS')
			window.location.reload()
		}
	})
}

// HTTP response 拦截器
service.interceptors.response.use(
	(response) => {
		// 配置了blob,不处理直接返回文件流
		if (response.config.responseType === 'blob') {
			if (response.status === 200) {
				return response
			} else {
				message.warning('文件下载失败或此文件不存在')
				return
			}
		}
		// 检查并存储授权信息
		checkAndStoreAuthentication(response)

		const data = response.data
		const code = data.code
		if (reloadCodes.includes(code)) {
			if (!loginBack.value) {
				error()
			}
			return
		}
		if (code !== 200) {
			if (code === 401) {
				clearAccessTokens()
			}
			const customErrorMessage = response.config.customErrorMessage
			const ignoreError = response.config.ignoreError //如果忽略错误就不输出错误消息
			if (!ignoreError) {
				message.error(customErrorMessage || data.msg)
			}
			return Promise.reject(data)
			// 自定义错误提示,覆盖后端返回的message
			// 使用示例:
			// export function customerList (data) {
			//   return request('list', data, 'get', {
			//     customErrorMessage: '自定义错误消息提示'
			//   });
			// }
		} else {
			// 统一成功提示
			const responseUrl = response.config.url
			const apiNameArray = [
				'add',
				'edit',
				'delete',
				'update',
				'grant',
				'reset',
				'start',
				'stop',
				'pass',
				'disable',
				'enable',
				'revoke',
				'suspend',
				'active',
				'turn',
				'adjust',
				'reject',
				'copy'
			]
			//指定方法不提示
			const noMessageApiNameArray = []
			apiNameArray.forEach((apiName) => {
				let responseApiArray = responseUrl.split('/') //分割
				let method = responseApiArray[responseApiArray.length - 1] //取最后一个
				let result = noMessageApiNameArray.includes(method)
				if (!result && responseUrl.includes(apiName)) {
					message.success(data.msg)
				}
			})
		}
		return Promise.resolve(data.data)
	},
	(error) => {
		if (error) {
			const status = 503
			const description = errorCodeMap[status]
			notification.error({
				message: '请求错误',
				description
			})
			return Promise.reject(status)
		}
	}
)

export const baseRequest = (url, value = {}, method = 'post', options = {}) => {
	if (sysConfig.VITE_PROXY === 'false') url = sysConfig.API_URL + url //判断是否要走代理模式,走了的话发布之后直接nginx代理
	if (method === 'post') {
		return service.post(url, value, options)
	} else if (method === 'get') {
		return service.get(url, { params: value, ...options })
	} else if (method === 'formdata') {
		// form-data表单提交的方式
		return service.post(url, qs.stringify(value), {
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
			},
			...options
		})
	} else {
		return service({
			method: method,
			url,
			data: value,
			...options
		})
	}
}

/**
 * 检查并存储授权信息
 * @param res 响应对象
 */
function checkAndStoreAuthentication(res) {
	// 读取响应报文头 token 信息
	var accessToken = res.headers[accessTokenKey]
	var refreshAccessToken = res.headers[refreshAccessTokenKey]

	// 判断是否是无效 token
	if (accessToken === 'invalid_token') {
		clearAccessTokens()
	}
	// 判断是否存在刷新 token,如果存在则存储在本地
	else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
		tool.data.set(accessTokenKey, accessToken)
		tool.data.set(refreshAccessTokenKey, refreshAccessToken)
	}
}

/**
 * 解密 JWT token 的信息
 * @param token jwt token 字符串
 * @returns <any>object
 */
function decryptJWT(token) {
	token = token.replace(/_/g, '/').replace(/-/g, '+')
	var json = decodeURIComponent(escape(window.atob(token.split('.')[1])))
	return JSON.parse(json)
}

/**
 * 将 JWT 时间戳转换成 Date
 * @description 主要针对 `exp`,`iat`,`nbf`
 * @param timestamp 时间戳
 * @returns Date 对象
 */
function getJWTDate(timestamp) {
	return new Date(timestamp * 1000)
}

// 模块内的请求, 会自动加上模块的前缀
export const moduleRequest =
	(moduleUrl) =>
	(url, ...arg) => {
		return baseRequest(moduleUrl + url, ...arg)
	}

export default service

  • 使用
import { baseRequest } from '@/utils/request'

const request = (url, ...arg) => baseRequest(`/auth/${url}`, ...arg)

export default {
	// 会话统计
	monitorAnalysis(data) {
		return request('session/analysis', data, 'get')
	}
	}

Axios 的 service.post() 方法的第三个参数 options 是一个可选的配置对象,可以传递一些额外的配置项,用于控制请求行为。以下是一些常用的 options 配置项:
params:对象类型,用于指定请求的查询参数(即 URL 上的参数),默认值为 {}。
headers:对象类型,用于指定请求的头部信息。
responseType:字符串类型,用于指定响应的数据类型。可以是 ‘json’、‘text’、‘arraybuffer’、‘blob’ 等类型。
timeout:数值类型,用于指定请求的超时时间(单位:毫秒),默认值为 0,表示没有超时限制。
withCredentials:布尔类型,指示是否在跨域请求中发送凭证(即 Cookie 等敏感信息),默认值为 false。
transformRequest:为函数类型或以数组形式存储的函数类型,用于在请求数据发送到服务器之前修改请求数据。数组形式时数组的元素需要为函数类型。
transformResponse:为函数类型或以数组形式存储的函数类型,用于在响应数据传递到 then 或 catch 前修改响应数据。数组形式时数组的元素需要为函数类型。
还有其他一些可选配置项,具体可以查看 Axios 的官方文档。

下面是一个示例代码,演示如何使用 options 配置项:

const service = axios.create({
  baseURL: '/api',
  timeout: 5000
});

service.post('/login', {
  username: 'admin',
  password: '123456'
}, {
  headers: {
    'Content-Type': 'application/json'
  },
  timeout: 3000
}).then(response => {
  console.log(response.data);
}).catch(error => {
  console.error(error);
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值