Axios二次封装

517 阅读6分钟

客户端向服务器端请求数据主要有ajax,axios,fetch方法。ajax是最原始的方法,而fetch是浏览器内置的api,是请求的另一种方式,它相对于ajax的最大好处之一就是天生是基于Promise原理的,可以实现异步请求。而axios是基于ajax和Promise封装的库。这次简要谈下ajax的使用,主要记录axios的二次封装。

@TOC


一、ajax发送请求的步骤

1.创建XMLHttpRequest实例对象

代码如下:

var XMLHttpRequest = new XMLHttpRequest();

2.创建HTTP 请求

代码如下:

XMLHttpRequest.open(method,URL,async,username,password)
  • method :用于请求的 HTTP 方法。包括 GET 、POST、HEAD、PUT、DELETE(不区分大小写)
  • url :请求的路径。
  • async :指示请求使用应该异步执行。如果这个参数为 false,代表请求是同步的,后续对 send() 的调用将阻塞,直到响应完全接受;如果这个参数是 true 或省略,请求是异步的,且通常需要一个 onreadystatechange 事件句柄
  • username 和 password :可选。

3.发送HTTP请求

使用 XMLHttpRequest .send() 来发送请求。

XMLHttpRequest.send(data)  
// 其中data是个可选参数,如果请求的数据不需要参数,即可以使用null来替代。

4.接收返回的数据——设置响应HTTP 请求状态变化的函数

从创建XMLHttpRequest对象,到发送数据、接收数据,一共会经历5种状态。对应的readyState属性值为0,1,2,3,4。当请求被发送到服务器且响应数据时,需要执行一些基于响应的操作,这些操作在onreadystatechange事件中执行,每当readyState改变时,就会触发onreadystatechange事件。

  • 0 刚创建XMLHttpRequest对象,对象处于未初始化状态。
  • 1: 对象使用open()方法创建了HTTP请求,对象处于初始化状态。
  • 2: 对象使用send()方法发送数据,对象处于发送数据状态。
  • 3: 请求处理中,响应中已有部分数据生产。XMLHttpRequest对象处于接收数据状态。
  • 4: 响应已完成,可以获取并使用响应中的数据。比如responseText属性或responseXml属性。

要想从服务器端获得返回的数据,就必须先判断 XMLHttpRequest 对象的状态。在函数里判断 XMLHttpRequest 对象的 readyState 值,如果readyState === 4 ,表示异步调用过程完毕,则使用 responseText 属性或 responseXml 属性来获取数据,但是异步调用过程完毕,并不代表异步调用成功,还要判断 XMLHttpRequest 对象的status属性值,只有status === 200 ,才表示异步调用成功。

注意:若HTML文件不是在Web 服务器上运行,而是在本地运行,则 xmlHttpRequest.status 的返回值为 0。 代码如下:

XMLHttpRequest.onreadystatechange = getData; 
function getData(){
    if(xmlHttpRequest.readyState === 4){
        if(xmlHttpRequest.status === 200 || xmlHttpRequest.status === 0 ){
            // 获取数据的语句
            document.write(xmlHttpRequest.responseText);
        }
    }
 }

二、axios的二次封装

1. 普通axios的使用

安装axios 引入axios

import axios from 'axios'
axios.get(url,{
	params:{
		name:'wmh'
	}
}).then(res=>{})
.catch(err=>{})

2. axios的二次封装

封装原因:把公共部分都提前封装,以后每次使用直接调用封装好的库,操作起来更加方便。

(1)先准备好接口—使用mock来模拟生成数据

什么是mock

mock在线网站注册登录并创建项目(此处创建的是登录页面的后台数据)

在这里插入图片描述 在这里插入图片描述 写好接口后点击保存,再将上面的mock接口根地址复制,以备后续使用。

(2)根据不同的环境变量来定义不同的请求接口

在真正的项目开发中,一般是会分环境来请求接口的,一般有3个分别为开发环境,测试环境和生产环境。(在vite构建的vue3项目中),在src目录下创建一个config文件夹,在文件夹下创建index.js文件,在里面设置3种环境变量,每种环境请求对应的接口,mock地址统一。并导出项目所处的环境变量。vite创建的vue项目中,获取环境变量要用import.meta.env。 代码如下: config—index.js

// 环境配置封装
// 获取环境变量
// 定义不同的环境中的api地址
const env = import.meta.env.MODE || 'prod'
const EnvConfig = {
    dev:{//开发环境调用的api
        baseApi:'/',
        mockApi:'https://www.fastmock.site/mock/756115e95fd471a83e21dd95ac29bcd6/api'
    },
    test:{//测试环境调用的api
        baseApi:'//test.futurefe.com/api',
        mockApi:'https://www.fastmock.site/mock/756115e95fd471a83e21dd95ac29bcd6/api'
    },
    prod:{//生产环境调用的api
        baseApi:'//futurefe.com/api',
        mockApi:'https://www.fastmock.site/mock/756115e95fd471a83e21dd95ac29bcd6/api'
    }
}
//导出环境变量
export default{
    env,
    mock:true,
    ...EnvConfig[env]//解构
}

(3)创建实例添加配置

在src目录下创建一个utils目录,在目录下创建一个index.js文件。创建一个axios实例,并添加全局配置。

utils—request.js

import axios from "axios";
import config from "../config";
import qs from 'qs'
//创建axios实例对象,添加全局配置
const serve = axios.create({
    baseURL:config.baseApi,
    timeout:8000
})
//按需配置,还可以配置其他的,比如跨域是否允许携带凭证以及传递的数据格式(看服务器要求什么格式)
//serve.default.withCredencials = true
//serve.default.headers['Content-Type']='application/x-www-form-urlencoded'
//若是post请求,还能用transformRequest来转换数据的格式,transformRequest只对post有效。
//serve.default.transformRequest = data => qs.stringify(data)
//qs是第三方库
//qs.stringify(data)将对象序列化为url格式xxx=xxx&xxx=xxx...
//qs.parse(data)将url解析成对象

(4)设置请求拦截器

客户端发送请求——请求拦截器——服务器端 utils—request.js

serve.interceptors.request.use((req)=>{
    //TO-DO
    const head = req.headers
    if(!head.Authorization) head.Authorization = "Bear jack"
    return req
})

请求拦截器拦截可以对请求头添加配置,再返回给服务器。

(5)设置响应拦截器

服务端响应数据——响应拦截器——客户端接收 成功状态:直接返回数据 失败状态: 服务器返回失败信息:可能是登录异常(根据不同的状态码做相应处理),抛出异常 服务器连信息都没返回:(服务端出错)提示网络异常

utils—request.js

//响应拦截
import axios from "axios";
import config from "../config";
import { ElMessage } from "element-plus";
import router from "../router";
const TOKEN_INVALID = 'Token认证失败,请重新登录'
const NETWORK_ERROR = '网络请求异常,请稍后重试'

serve.interceptors.response.use((res)=>{
    //TO-DO
    const {code,data,msg} = res.data
    //成功
    if(code===200){
        return data
    }
    //登录报错
    else if(code === 401){
        ElMessage.error(TOKEN_INVALID)
        //捕获到错误给点时间再跳转页面
        setTimeout(()=>{
            router.push('/login')
        },15000)
        //用Promise.reject来抛出异常
        return Promise.reject(TOKEN_INVALID)
    }
    else{
        ElMessage.error(msg||NETWORK_ERROR)
        return Promise.reject(msg||NETWORK_ERROR)
    }
})

(6)设置请求的核心函数

function request(options){
	//请求有指明请求方法则使用请求方法否则默认为'get’请求
    options.method = options.method || 'get'
    if(options.method.toLowerCase() === 'get'){//大小写
        options.params = options.data
    }
    //生产环境下防止其调用mock的api
    if(config.env === 'prod'){
        serve.defaults.baseURL = config.baseApi
    }
    else{
        serve.defaults.baseURL = config.mock?config.mockApi:config.baseApi
    }
    return serve(options)
}

(7)导出封装好的对象

export default request

(8)在main.js中配置全局挂载对象

main.js中添加以下代码

import request from './utils/request'
//挂载全局对象:可全局使用
app.config.globalProperties.$request = request

(9)在login页面中验证

<script>
  import Welcome from './Welcome.vue'
    export default{
      name:'login',
      components:{Welcome},
      mounted(){
        this.$request({
          method:'get',
          url:'/login',
          data:{
            name:'jack'
          }
        }).then((res)=>{
          console.log(res)
        })
      },
      methods:{
        goHome(){
          this.$router.push('/welcome')
        }
      }
    }
  </script>
  <template>
    <div>
      <h1>欢迎来到登录界面</h1>
      <el-button @click="goHome">回首页</el-button>
    </div>
  </template> 
  <style>
  </style>

添加的代码:

mounted(){
        this.$request({
          method:'get',
          url:'/login',
          data:{
            name:'jack'
          }
        }).then((res)=>{
          console.log(res)
        })
      }
//上述的options即$request内的内容。

(10)控制台结果

在这里插入图片描述

在这里插入图片描述