前端网络请求之JavaScript XHR、Fetch、Axios

一、JavaScript XHR、Fetch

AJAX:一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新。在不重新加载整个网页的情况下,对网页的某部分进行更新
Fetch:基于 promise 设计的。Fetch 的代码结构比起 ajax 简单多。fetch 不是 ajax 的进一步封装,而是原生 js,没有使用 XMLHttpRequest 对象

1.1 前端数据请求方式

  • 后端:服务器端

  • 服务器端渲染 SSR(后端渲染):全部都是后端开发的

    • 客户端发送请求
    • 服务端接收请求并利用 jsp/asp/php 返回相应 HTML 文档
    • 页面刷新,客户端加载新的HTML文档
  • SSR 的缺点

    • 页面本质上只有一些数据发生了变化,而服务器却要重绘整个页面,违背了 DRY(Don’t repeat yourself)原则
    • 给网络带宽带来不必要的开销
  • 前后端分离(客户端渲染、前端渲染)

    • 后端只需要关心 API 服务器(提供数据的服务器)和数据库
    • AJAX:
      • 在不重新刷新网页的情况下与服务器通信,交换数据,或更新页面(无页面刷新获取服务器数据的技术)
      • 接收并使用从服务器发来的数据
      • 异步的 JavaScript 和 XML(不用了,现在使用 Json)

1.2 HTTP

  • 超文本传输协议:用于分布式、协作式和超媒体信息系统的应用层协议
  • 最早是为了接收 html 页面,浏览器进行渲染
  • http 是一个客户端和服务端之间请求和响应的标准
  • 通过 HPPT 或者 HTTPS( http上增加的一个安全层)协议请求的资源由统一资源标识符 URL 来标识
    • 通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)
      • 这个客户端为用户代理程序(user agent)
    • 响应的服务器上存储着一些资源,比如 HTML文件和图像
      • 这个响应服务器为源服务器(origin server)
  • http 就是和服务器沟通的一种协议:请求对象、响应对象
  • 网页中的资源通常是被放在 web 资源服务器中,由浏览器自动发送 http 请求来获取、解析、展示的

1.3 网页中资源的获取

  • 网页中的资源通常是被放在 Web 资源服务器中,由浏览器自动发送 HTTP 请求来获取、解析、展示的
  • **页面中很多数据是动态展示的:**页面中的数据展示、搜索数据、表单验证等等,也是通过在 JavaScript 中发送 HTTP 请求获取的

1.4 HTTP 的组成

  • 一次 http 请求主要包括:请求和响应

  • 请求

    • 请求行:方法(请求方式)、URL、协议版本(目前采用的是什么版本)

    • 请求头:客户端会默认传递过来一些信息

      • content-type:请求携带的数据类型(告诉服务器现在传送的数据以什么形式传过去)

        • application/x-www-form-urlencoded:以&分隔的键值对(以=分隔)
        • application/json:{“”:“”}json类型
        • text/plain:普通文本 ×
        • application/xml:少用,xml类型
        <xml><name>lili</name>
        </xml>
        
        • multipart/form-data:上传文件,很多时候不需要手动设置
      • content-length:文件的大小长度

      • keep-alive:不立即断开,继续保持连接一会儿

        • node 开发服务器:保持五秒
        • http1.1 默认开启了
      • acept-encoding(接收的客户端):告知服务器,客户端支持接收的文件的压缩格式

        • zip/rar/7z
        • gzip(给你返回更小的压缩文件)
      • accept:我(客户端)能够接收的文件格式(一般为 json)

      • user-agent:客户端相关的信息

  • 响应

    • 响应行:协议版本、状态码、状态码的原因短语
      • 200 OK 请求成功
      • 201 Created POST请求,创建新的资源
      • 301 请求资源的URL已经修改,重定向
      • 大于四百:错误
      • 400 客户端的错误
      • 401 未授权的错误
      • 403 客户端没有权限访问
      • 404 服务器找不到请求的资源
      • 500 服务器错误,服务器不知道如何处理
      • 503 服务器不可用
    • 响应头
      • 拿到响应数据:xhr.response
      • 可以设置接收的类型:xhr.responseType="json"默认是text
    • 响应体

1.5 HTTP 的版本

  • HTTP/0.9 版本:1991年,只支持 get 请求方法获取文本数据
  • HTTP/1.0:TCP连接
  • HTTP/1.1(使用最广泛)
    • 发布于1997年
    • 增加了PUT、DELETE等请求方法
    • 采用持久连接(Connection: keep-alive),多个请求可以共用同一个 TCP 连接
  • HTTP/2.0
  • HTTP/3.0

1.6 HTTP 的请求方式

  • 发送一次请求如何同服务器进行沟通
  • RFC(版本规范)中定义了一组请求方式,标识要对给定资源执行的操作
    • GET:请求数据,获取数据
    • HEAD:返回的数据没有响应体
    • POST:提交数据
    • PUT:替代目标资源
    • DELETE:删除数据
    • PATCH:修改数据
    • CONNECT:代理服务器
    • TRACE:消息环回测试

1.7 AJAX 发送请求

  • 第一种方式

    • 创建 XMLHttpRequest 对象

    • 监听状态的改变(宏任务)

      • 一次网络请求中状态发生了很多次变化,数字表示状态
        • 0(不监听):代理被创建
        • 1 (open):open 方法已经被调用
        • 2(send):send 方法已经被调用,并且头部和状态已经可获得
        • 3(下载中)
        • 4:DONE 已完成
      • 这个状态并非是 HTTP 的相应状态,而是记录的 XMLHttpRequest 对象的状态变化:http 响应状态通过 status 获取
      • **发送同步请求:**将 open 的第三个参数设置为 false
        • 发送请求(浏览器帮助发送对应的请求):实际开发使用异步请求,不会阻塞js代码继续执行: xhr.open("get", "http://123.207.32.32:8000/home/multidata", false)
    • 除了 onreadystatechange 还有其他的事件可以监听

      • loadstart:请求开始
      • progress:文件上传
      • abort:取消了请求
      • load:请求成功完成
      • loadend
      • error:发生连接错误
      • onload:只调用一次
      • timeout:请求超时
    • 配置请求

      • open方法来配置,参数如下:

      • method:请求的方式

      • URL:请求的地址

        • json 类型的接口(90%)
        • text 类型的接口
        • xml 类型的接口
        // 1.const xhr = new XMLHttpRequest()// 2.onload监听数据加载完成xhr.onload = function() {// const resJSON = JSON.parse(xhr.response)console.log(xhr.response)// console.log(xhr.responseText)// console.log(xhr.responseXML)}// 3.告知xhr获取到的数据的类型xhr.responseType = "json"// xhr.responseType = "xml"// 4.配置网络请求// 4.1.json类型的接口xhr.open("get", "http://xxxxx")// 4.2.json类型的接口// xhr.open("get", "http://xxxxx/hello_json")// 4.3.text类型的接口// xhr.open("get", "http://xxxxx/hello_text")// 4.4.xml类型的接口// xhr.open("get", "xxxxx/hello_xml")// 5.发送网络请求xhr.send()
    
<script>// xhr四步骤:// 1. 创建XMLHttpRequest对象// 所有的东西都放在了 xhr 里面const xhr = new XMLHttpRequest()// 2. 监听状态的改变(宏任务)xhr.onreadystatechange=function(){if(xhr.readyState!==XMLHttpRequest.DONE)return// 2.1将字符串转成JSON对象// const resJSON=JSON.parse(xhr.response)// const banners=resJSON.data.bannerlog(xhr.response)}// 告知xhr获取到的数据的类型,默认设置为textxhr.responseType="json"// 3. 调用open方法进行配置//open第三个参数boolean表示同步或者异步,默认true异步xhr.open("get","https://www.baidu.com"false)// 4. 调用send发送请求xhr.send()</script>

1.8 获取 http 的状态码

  • 前面都是记录 xhr 对象本身的状态变化,并非针对 http 的网络请求状态,http 网络请求的状态需要通过 .status 获取
 // 1.创建对象const xhr = new XMLHttpRequest()// 2.监听结果xhr.onload = function() {console.log(xhr.status, xhr.statusText)// 根据http的状态码判断是否请求成功if (xhr.status >= 200 && xhr.status < 300) {console.log(xhr.response)} else {console.log(xhr.status, xhr.statusText)}}xhr.onerror = function() {console.log("onerror", xhr.status, xhr.statusText)}// 3.设置响应类型xhr.responseType = "json"// 4.配置网络请求// xhr.open("get", "http://xxxxx/abc/cba/aaa")xhr.open("get", "http://xxxxx/home/multidata")// 5.发送网络请求xhr.send()

1.9 Get、Post 请求传参

  • 要不要传递数据取决于接口需不需要数据
  • url
    • 主机地址
    • 服务器端口号
    • 路径
  • 常见的传递给服务器数据的方式有如下几种:
    • 方式一:GET 请求的 query 参数
      • 缺点:以明文的形式直接放在对应的 URL,属于 URL 的一部分,没有那么安全;而 post 请求传递参数的方式有很多种
        • 放在请求体里面,FormData 是默认格式
    • 方式二:POST 请求 x-www-form-urlencoded 格式
    • 方式三:POST 请求 FormData 格式
    • 方式四:POST 请求 JSON 格式
   const formEl = document.querySelector(".info")const sendBtn = document.querySelector(".send")sendBtn.onclick = function() {// 创建xhr对象const xhr = new XMLHttpRequest()// 监听数据响应xhr.onload = function() {console.log(xhr.response)}// 配置请求xhr.responseType = "json"// 1.传递参数方式一: get -> query// xhr.open("get", "http://xxxx/get?name=lili&age=18&address=广州市")// 2.传递参数方式二: post -> urlencoded// xhr.open("post", "http://xxxx/posturl")// // 发送请求(请求体body)// xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")// xhr.send("name=lili&age=18&address=广州市")// 3.传递参数方式三: post -> formdata// xhr.open("post", "http://xxxx/postform")// 得将元素转成 form 对象// // formElement对象转成FormData对象// const formData = new FormData(formEl)// xhr.send(formData)// 4.传递参数方式四: post -> jsonxhr.open("post", "http://xxx/postjson")xhr.setRequestHeader("Content-type", "application/json")xhr.send(JSON.stringify({name: "lili", age: 18, height: 1.88}))}

1.10 ajax 网络请求封装

    function liliajax({url,method = "get",data = {},headers = {}, // tokensuccess,failure} = {}) {// 1.创建对象const xhr = new XMLHttpRequest()// 2.监听数据xhr.onload = function() {if (xhr.status >= 200 && xhr.status < 300) {success && success(xhr.response)} else {failure && failure({ status: xhr.status, message: xhr.statusText })}}// 3.设置类型xhr.responseType = "json"// 4.open方法// 一般不推荐写在 data 里面if (method.toUpperCase() === "GET") {// 对 data 进行遍历const queryStrings = []for (const key in data) {queryStrings.push(`${key}=${data[key]}`)}url = url + "?" + queryStrings.join("&")xhr.open(method, url)xhr.send()} else {xhr.open(method, url)xhr.setRequestHeader("Content-type", "application/json")xhr.send(JSON.stringify(data))}return xhr}// 调用者liliajax({url: "http://xxx/get",method: "GET",data: {name: "lili",age: 18},success: function(res) {console.log("res:", res)},failure: function(err) {// alert(err.message)}})// liliajax({//   url: "http://xxxx/postjson",//   method: "post",//   data: {//     name: "jsondata",//     age: 22//   },//   success: function(res) {//     console.log("res:", res)//   },//   failure: function(err) {//     // alert(err.message)//   }// })
function liliajax({url,method = "get",data = {},timeout = 10000,headers = {}, // token
} = {}) {// 1.创建对象const xhr = new XMLHttpRequest()// 2.创建Promiseconst promise = new Promise((resolve, reject) => {// 2.监听数据xhr.onload = function() {if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.response)} else {reject({ status: xhr.status, message: xhr.statusText })}}// 3.设置类型xhr.responseType = "json"xhr.timeout = timeout// 4.open方法if (method.toUpperCase() === "GET") {const queryStrings = []for (const key in data) {queryStrings.push(`${key}=${data[key]}`)}url = url + "?" + queryStrings.join("&")xhr.open(method, url)xhr.send()} else {xhr.open(method, url)xhr.setRequestHeader("Content-type", "application/json")xhr.send(JSON.stringify(data))}})promise.xhr = xhrreturn promise
}
    const promise = liliajax({url: "http://xxxx/get",data: {username: "lili",password: "123456"}})promise.then(res => {console.log("res:", res)}).catch(err => {console.log("err:", err)})

1.11 timeout、手动取消请求

  • timeout 浏览器达到过期时间还没有获取对应的结果,取消本次请求
  • 可以通过 abort 方法强制取消请求
  <button>取消请求</button><script>const xhr = new XMLHttpRequest()xhr.onload = function() {console.log(xhr.response)}xhr.onabort = function() {console.log("请求被取消掉了")}xhr.responseType = "json"// 1.超市时间的设置xhr.ontimeout = function() {console.log("请求过期: timeout")}// timeout: 浏览器达到过期时间还没有获取到对应的结果时, 取消本次请求// xhr.timeout = 3000xhr.open("get", "http://xxxxx/timeout")xhr.send()// 2.手动取消结果const cancelBtn = document.querySelector("button")cancelBtn.onclick = function() {xhr.abort()}</script>

1.12 认识 Fetch 和 Fetch API 发送网络请求

  • fetch 是 xhr 的代替方案,提供了更加现代的处理方案
  • 返回值是一个 Promise
    • 在请求发送成功时,调用 resolve 回调 then
    • 在请求发送失败时,调用 reject 回调 catch
  • 所有的操作并不是都在一个对象上面
  • fetch 函数的使用
    • 参数
      • input
        • 定义要获取的资源地址,可以是一个 URL 字符串,也可以使用一个 Request 对象(实验性特性)类型
      • init:其他初始化参数
        • method: 请求使用的方法,如 GET、POST
        • headers: 请求的头信息
        • body: 请求的 body 信息
    // 1.fetch发送get请求// 1.1.未优化的代码// fetch("xxxx").then(res => {//   // 1.获取到response//   const response = res//   // 2.获取具体的结果//   response.json().then(res => {//     console.log("res:", res)//   })// }).catch(err => {//   console.log("err:", err)// })// 1.2. 优化方式一:// fetch("xxxx").then(res => {//   // 1.获取到response//   const response = res//   // 2.获取具体的结果//   return response.json()// }).then(res => {//   console.log("res:", res)// }).catch(err => {//   console.log("err:", err)// })// 1.3. 优化方式二:// async function getData() {//   const response = await fetch("http://xxxxx")//   const res = await response.json()//   console.log("res:", res)// }// getData()// 2.post请求并且有参数async function getData() {// const response = await fetch("http://xxxxx/postjson", {//   method: "post",//   // headers: {//   //   "Content-type": "application/json"//   // },//   body: JSON.stringify({//     name: "lili",//     age: 18//   })// })const formData = new FormData()formData.append("name", "lili")formData.append("age", 18)const response = await fetch("http://xxxx/postform", {method: "post",body: formData})// 获取response状态console.log(response.ok, response.status, response.statusText)const res = await response.json()console.log("res:", res)}getData()

1.13 XMLHttpRequest 文件上传

  • 文件上传:头像上传、照片等

  • 通过表单传给服务器

  • 可以查看上传的进度

<input class="file" type="file"><button class="upload">上传文件</button><script>// xhr/fetchconst uploadBtn = document.querySelector(".upload")uploadBtn.onclick = function() {// 1.创建对象const xhr = new XMLHttpRequest()// 2.监听结果xhr.onload = function() {console.log(xhr.response)}xhr.onprogress = function(event) {console.log(event)}xhr.responseType = "json"xhr.open("post", "http://xxxxx/upload")// 表单const fileEl = document.querySelector(".file")const file = fileEl.files[0]const formData = new FormData()formData.append("avatar", file)xhr.send(formData)}</script>

1.14 Fetch 请求文件上传

 <input class="file" type="file"><button class="upload">上传文件</button><script>// xhr/fetchconst uploadBtn = document.querySelector(".upload")uploadBtn.onclick = async function() {// 表单const fileEl = document.querySelector(".file")const file = fileEl.files[0]const formData = new FormData()formData.append("avatar", file)// 发送fetch请求const response = await fetch("http://xxxx/upload", {method: "post",body: formData})const res = await response.json()console.log("res:", res)}</script>

二、网络请求库 - axios

Axios:是一种基于 Promise 封装的 HTTP 客户端。
特点如下:

  • 浏览器端发起 XMLHttpRequests 请求
  • node 端发起 http 请求
  • 支持 Promise API
  • 监听请求和返回
  • 对请求和返回进行转化
  • 取消请求
  • 自动转换 json 数据
  • 客户端支持抵御 XSRF 攻击

2.1 axios

  • 功能特点
    • 在浏览器中发送 XMLHttpRequests 请求
    • 在 node.js 中发送 http 请求
    • 支持 Promise API
      • fetch 也支持 promise
    • 拦截请求和响应
    • 转换请求和响应数据
  • axios: ajax i/o system

2.2 常见配置选项

  • 请求地址:url: ‘/user’,
  • 请求类型:method: ‘get’,
  • 请根路径:baseURL: ‘http://www.xxx.com/api’,
  • 请求前的数据处理:transformRequest:[function(data){}],
  • 请求后的数据处理:transformResponse: [function(data){}],
  • 自定义的请求头:headers:{‘x-Requested-With’:‘XMLHttpRequest’},
    • 由服务器决定
  • URL查询对象:params:{ id: 12 },
  • 查询对象序列化函数:paramsSerializer: function(params){ }
  • request body:data: { key: ‘aa’},
  • 超时设置:timeout: 1000,
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");// 1. baseURL 
const baseURL = "http://xxxxx:8000"
// 给axios实例配置公共的基础配置
axios.defaults.baseURL = baseURL
axios.defaults.baseURL = 10000
axios.defaults.headers = {}
// 1.1 get:
axios.get("/home/multidata").then(res => {console.log(res.data);
})// 1.2 get

2.3 axios 请求方式

  • 支持多种请求方式

    • axios(config)

    • axios.request(config)

    • axios.get(url[, config])

      • 能够直接在浏览器中敲回车发送的请求
    • axios.delete(url[, config])

    • axios.head(url[, config])

    • axios.post(url[, data[, config]])

    • axios.put(url[, data[, config]])

    • axios.patch(url[, data[, config]])

import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");//1. 发送 request请求:发送一些配置
axios.request({url: "http://xxxxx",method: "get",}).then((res) => {console.log(res.data);});// 2. 发送get请求:
// 传递参数:
// 2.1 querry参数
axios.get("http:/xxxxx/lyric?id=500665346", {}).then((res) => {console.log(res.data);
});// 2.2 params这个使用比较多
axios.get("http://xxxxx/lyric", {params: {id: 500665346,},}).then((res) => {console.log(res.data);});// 3. 发送 post 请求:post请求的 url 参数是不能拼接到后面的,只能放在请求体里面
// 两种写法
axios.post("http://xxxxx/postjson", {username: "lili",password: "123455",}).then((res) => {console.log(res.data);});axios.post("http://xxxxx/postjson", {data: {username: "lili",password: "123455",},}).then((res) => {console.log(res.data);});
  • 同时发送两个请求
    • 使用 axios.all, 可以放入多个请求的数组
    • axios.all([]) 返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2
// 2. axios 发送多个请求
// Promise.all
axios.all([axios.get("/xxx/multidata"),axios.get("/xxx/multidata2")]).then(res => {console.log(res.data);
})

2.4 axios 创建实例

  • 对于单独的 url 会创建单独的实例
  • 看开发过程中有多少个实例
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");// axios 默认库提供给我们的实例对象
axios.get("http://xxxxx/lyric?id=500665346");
// 创建其他的实例发送网络请求
const instance1 = axios.create({baseURL: "http://xxxx",timeout: 6000,headers: {},
});
instance1.get("/lyric", {params: {id: 500665346,},
});
const instance2 = axios.create({baseURL: "http://xxxxx",timeout: 9000,headers: {},
});

2.5 请求和响应拦截器

  • 在发出网络请求之前
    • 请求成功
      • 显示 loading 动画
      • 对原来的配置文件进行修改
        • header
        • 认证登陆:传入 token、cookie
        • 对请求参数进行某些转化
  • 在得到响应结果之前
    • 响应成功
      • 结束 loading 动画
      • 对数据进行转化,再返回数据
  • 进行处理
// 对实例配置拦截器
axios.interceptors.request.use(请求成功回调拦截, 请求失败回调拦截);
// 一般都不会请求失败
axios.interceptors.request.use((config) => {if (config.url === "user/info") config.headers["token"] = "lili";// 请求成功的拦截return config;},(err) => {console.log("请求失败的拦截,基本上不会发生");}
);
// 400 404 请求失败
axios.interceptors.response.use(成功回调, 失败回调);
axios.interceptors.response.use((res) => {// 这里对响应的结果进行转化// 在得到结果的时候就不需要 res.data 了// 响应成功的拦截return res.data;},(err) => {// 响应失败的拦截return err;}
);
axios.get("http://xxxxx/lyric?id=500665346").then((res) => {console.log(res);}).catch((err) => {console.log(err);});

2.6 封装

import axios from "axios";
class LiliRequest {constructor(baseURL, timeout = 10000) {// 创建一个实例进行配置this.instance = axios.create({baseURL,timeout})}request(config) {return new Promise((resolve, reject) => {this.instance.request(config).then((res) => {resolve(res.data);}).catch((err) => {reject(err);});});}get(config) {return this.request({ ...config, method: "get" });}post(config) {return this.request({ ...config, method: "post" });}
}
const liliRequest1 = new LiliRequest("http://www.baidu.com")
const liliRequest2 = new LiliRequest("http://www.taobao.com")export default new LiliRequest()
import liliRequest from './service/index'

三、TypeScript - axios 封装

3.1 基本封装

import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
class LiliRequest {instance: AxiosInstance;// 1. 创建实例// request 实例 => axios实例constructor(config: AxiosRequestConfig) {this.instance = axios.create(config);}// 2. 封装网络请求的方法request(config: AxiosRequestConfig) {return this.instance.request(config)}get() { }}
export default LiliRequest;

拦截器

  • 全局拦截
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
class LiliRequest {instance: AxiosInstance;// 1. 创建实例// request 实例 => axios实例constructor(config: AxiosRequestConfig) {this.instance = axios.create(config);// 每个instance实例都添加拦截器// 传入一个config对config进行修改再返回this.instance.interceptors.request.use((config) => {//  loading/tokenconsole.log("全局请求成功的拦截");return config;},(err) => {console.log("全局请求失败的拦截");return err;});this.instance.interceptors.response.use((res) => {console.log("全局响应成功的拦截");return res;},(err) => {console.log("全局响应失败的拦截");return err;});}// 2. 封装网络请求的方法request(config: AxiosRequestConfig) {return this.instance.request(config);}get() {}
}
export default LiliRequest;
  • 针对特定的请求做拦截器
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {instance: AxiosInstance;// 1. 创建实例// request 实例 => axios实例constructor(config: LiliRequestConfig) {this.instance = axios.create(config);// 每个instance实例都添加拦截器// 传入一个config对config进行修改再返回this.instance.interceptors.request.use((config) => {//  loading/tokenconsole.log("全局请求成功的拦截");return config;},(err) => {console.log("全局请求失败的拦截");return err;});this.instance.interceptors.response.use((res) => {console.log("全局响应成功的拦截");return res;},(err) => {console.log("全局响应失败的拦截");return err;});// 同时存在不存在覆盖// 判断请求是否添加拦截器,针对每一个请求做精细化处理// 针对特定的liliRequest实例添加拦截器// if (config.interceptors) {//类型缩小this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);// }}// 2. 封装网络请求的方法request(config: AxiosRequestConfig) {return this.instance.request(config);}get() {}
}
export default LiliRequest;
  • LiliRequest 类单次请求:针对不同的需求创建不同的拦截
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {instance: AxiosInstance;// 1. 创建实例// request 实例 => axios实例constructor(config: LiliRequestConfig) {this.instance = axios.create(config);// 每个instance实例都添加拦截器// 传入一个config对config进行修改再返回this.instance.interceptors.request.use((config) => {//  loading/tokenconsole.log("全局请求成功的拦截");return config;},(err) => {console.log("全局请求失败的拦截");return err;});this.instance.interceptors.response.use((res) => {console.log("全局响应成功的拦截");return res;},(err) => {console.log("全局响应失败的拦截");return err;});// 同时存在不存在覆盖// 判断请求是否添加拦截器,针对每一个请求做精细化处理// 针对特定的liliRequest实例添加拦截器// if (config.interceptors) {//类型缩小this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);// }}// 2. 封装网络请求的方法request(config: LiliRequestConfig) {// 拦截器的本质是一些钩子函数,对其进行回调if (config.interceptors?.requestSuccessFn) {config = config.interceptors.requestSuccessFn(config);}return new Promise((resolve, reject) => {this.instance.request(config).then((res) => {if (config.interceptors?.responseSuccessFn) {res = config.interceptors.responseSuccessFn(res);}resolve(res);}).catch((err) => {reject(err);});});}get() {}
}
export default LiliRequest;

3.2 返回结果的类型处理

  • 返回结果是一个 unknown 类型
  • 网络请求
import liliRequest from "..";
interface IHmoeData{data: any,returnCode: string,success:boolean
}
liliRequest.request<IHmoeData>({url:"/user/name"
}).then(res => {console.log(res);})
  • 封装类
 // 2. 封装网络请求的方法request<T=any>(config: LiliRequestConfig) {// 拦截器的本质是一些钩子函数,对其进行回调if (config.interceptors?.requestSuccessFn) {config = config.interceptors.requestSuccessFn(config);}return new Promise<T>((resolve, reject) => {this.instance.request<any,T>(config).then((res) => {if (config.interceptors?.responseSuccessFn) {// res = config.interceptors.responseSuccessFn(res);}resolve(res);}).catch((err) => {reject(err);});});}

3.3 接口类型中的泛型处理

  • 封装类
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {instance: AxiosInstance;// 1. 创建实例// request 实例 => axios实例constructor(config: LiliRequestConfig) {this.instance = axios.create(config);// 每个instance实例都添加拦截器// 传入一个config对config进行修改再返回this.instance.interceptors.request.use((config) => {//  loading/tokenconsole.log("全局请求成功的拦截");return config;},(err) => {console.log("全局请求失败的拦截");return err;});this.instance.interceptors.response.use((res) => {console.log("全局响应成功的拦截");return res.data;},(err) => {console.log("全局响应失败的拦截");return err;});// 同时存在不存在覆盖// 判断请求是否添加拦截器,针对每一个请求做精细化处理// 针对特定的liliRequest实例添加拦截器// if (config.interceptors) {//类型缩小this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);// }}// 2. 封装网络请求的方法request<T=any>(config: LiliRequestConfig<T>) {// 拦截器的本质是一些钩子函数,对其进行回调if (config.interceptors?.requestSuccessFn) {config = config.interceptors.requestSuccessFn(config);}return new Promise<T>((resolve, reject) => {this.instance.request<any,T>(config).then((res) => {if (config.interceptors?.responseSuccessFn) {// res = config.interceptors.responseSuccessFn(res);}resolve(res);}).catch((err) => {reject(err);});});}get() {}
}
export default LiliRequest;
  • 修改类型
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 针对AxiosRequestConfig配置进行扩展
export interface LILIInterceptors<T=AxiosResponse> {requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;requestFailureFn?: (err: any) => any;responseSuccessFn?: (res: T) => T;responseFailureFn?: (err: any) => any;
}
export interface LiliRequestConfig<T=AxiosResponse> extends AxiosRequestConfig {interceptors?: LILIInterceptors<T>;
}

3.4 添加其他请求方式

  get<T = any>(config: LiliRequestConfig<T>) {return this.request({...config,method:"GET"})}post<T = any>(config: LiliRequestConfig<T>) {return this.request({...config,method:"POST"})}delete<T = any>(config: LiliRequestConfig<T>) {return this.request({...config,method:"DELETE"})}patch<T = any>(config: LiliRequestConfig<T>) {return this.request({...config,method:"PATCH"})}

3.5 总结

  • 拦截器进行精细控制
    • 全局拦截器
    • 实例拦截器
    • 单次请求拦截器
  • 响应结果的类型处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/647945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

主流电商平台:item_get-通过商品ID取商品详情,主图,sku

随着全球化的加速和互联网技术的不断发展&#xff0c;跨境电商已经成为了全球商业的重要组成部分。在这个环境下&#xff0c;如何有效地获取商品详情成为了关键的问题。本文将探讨一种基于商品ID获取商品详情的跨境电商创新方式&#xff0c;即item_get接口&#xff0c;以及其潜…

Vue3-在HTML标签、组件标签上使用v-model

本篇为Vue3学习中遇到的v-model相关的记录&#xff0c;如有问题欢迎指正 一、在标签上使用v-model v-model通常在input、select等标签上来实现数据双向绑定 <input type"text" v-model"username"> 原理&#xff1a;v-model通过给标签value赋值来实…

Windows10上使Git Bash支持rsync命令操作步骤

rsync命令是linux上常用的工具之一&#xff0c;用于远程以及本地系统中拷贝/同步文件和文件夹。 Windows Git Bash默认并不支持rsync&#xff0c;如下图所示&#xff1a; 使Git Bash支持rsync命令操作步骤&#xff1a; 1.从https://repo.msys2.org/msys/x86_64/ 下…

一、MongoDB、express的安装和基本使用

数据库【Sqlite3、MongoDB、Mysql】简介&小记 Sqlite3&#xff1a; SQLite3是一个轻量级的数据库系统&#xff0c;它被设计成嵌入式数据库。这意味着它是一个包含在应用程序中的数据库&#xff0c;而不是独立运行的系统服务。适用场景&#xff1a;如小型工具、游戏、本地…

算力总规模位列全球第二!中创:助推数据中心建设

近日&#xff0c;国新办举办新闻发布会&#xff0c;介绍2023年工业和信息化发展情况。算力、数据中心、云计算等与数字化转型、能源利用息息相关&#xff0c;被多次提及。 工业和信息化部新闻发言人、运行监测协调局局长陶青表示&#xff1a; 数字基础设施支撑有力&#xff0c;…

力扣算法-Day18

18.四数之和 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&#xff1…

关于数据库被勒索如何解决?

今天发现数据库被删&#xff0c;原因是勒索病毒&#xff0c;这期文章来说明下: **使用binlog日志恢复**&#xff1a; - **确认binlog状态**&#xff1a;检查MySQL服务器是否开启了binlog日志功能。如果服务器启用了binlog&#xff0c;那么在数据被篡改之前的操作都有可能被记…

golang 根据URL获取文件名

只有一个文件地址&#xff0c;但是没有文件名称&#xff0c;文件地址&#xff1a;http://XXXXXXX/getfile.aspx?fileid999 但是系统需要把文件名称也写入到数据库 可以根据 resp.Header["Content-Disposition"] 获取文件名 resp.Header["Content-Disposition&q…

继承和原型链

基于原型链的继承示例 // 继承方法 const parent { value: 2, method() { console.log(this); return this.value 1 } } console.log(parent.method());//3 不难理解 const child { __proto__: parent, } console.log(child.method());//3 this 指向child 但是属性中没有v…

亚马逊鲲鹏系统:批量注册买家号的新利器

近年来&#xff0c;随着电商市场的迅速发展&#xff0c;亚马逊作为全球最大的在线零售平台之一&#xff0c;其买家号的需求也日益增长。而亚马逊鲲鹏系统是一个能够批量全自动注册亚马逊买家号的系统。而对于全自动批量注册&#xff0c;账号资料方面&#xff0c;也有一定的要求…

vue3 + antd 封装动态表单组件(二)

传送带&#xff1a; vue3 antd 封装动态表单组件&#xff08;一&#xff09; 前置条件&#xff1a; vue版本 v3.3.11 ant-design-vue版本 v4.1.1 vue3 antd 封装动态表单组件&#xff08;一&#xff09;是基础版本&#xff0c;但是并不好用&#xff0c; 因为需要配置很多表…

【QT+QGIS跨平台编译】之八:【zstd+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、zstd介绍二、文件下载三、文件分析四、pro文件五、编译实践一、zstd介绍 ZSTD(Zstandard的缩写),是一种快速压缩算法,提供了高压缩比功能。ZSTD还为小数据提供了一种特殊的模式,称为字典压缩。ZSTD库使用BSD许可证作为开放源码软件提供的。它的格式是稳定的,…

【java题解】题目 1779: 你的第一个程序;题目 1779: 你的第一个程序;题目 1173: 计算球体积

目录 题目 1779: 你的第一个程序 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1173: 计算球体积 题目描述 输入格式 输出格式 样例输入 样例输出 题解 题目 1267: AB Problem 题目描述 输入格式 输出格式 样例输入 样例输出 题解 从今天开始…

CANoe的python API,使用python控制CANoe工具

CANoe是一款用于开发、测试和仿真汽车通信系统的工具&#xff0c;它提供了Python API&#xff0c;使得开发者可以使用Python脚本来控制CANoe工具的各项功能。 CANoe的Python API提供了丰富的功能&#xff0c;可以用于配置网络和节点、发送和接收消息、执行测量和仿真等。 注意…

TS学习笔记十:装饰器及三斜线指令

本节介绍TS中的装饰器和三斜线指令&#xff0c; 装饰器&#xff08;Decorators&#xff09;为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。   三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。 讲解视频 20240116-205052装饰器…

基于一款热门大屏可视化设计器使用教程

乐吾乐大屏可视化设计器是一个用于创建和定制大屏幕数据可视化展示的工具&#xff0c;支持零代码实现物联网、工业智能制造等领域的可视化大屏、触摸屏端UI以及工控可视化的解决方案。同时也是一个Web组态工具&#xff0c;支持2D、3D等多种形式&#xff0c;用于构建具有实时数据…

华硕ASUS K43SD笔记本安装win7X64(ventoy为入口以支撑一盘多系统);友善之臂mini2440开发板学习

记录 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 1. MBR样式常规安装win7X64Sp1 (华硕 K43SD 安装 win7X64 ) 老爷机 白色 华硕 K43SD 笔记本 安装 win7X64 (常规安装) 设置: 禁用UEFI 启用AHCI ventoy制作MBR(非UEFI)方式的启动U盘 U盘中放cn_windows_7_ultimate_wit…

TCP 三次握手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…

【机器学习300问】19、深度学习和机器学习什么关系?

之前的文章都聚焦在传统的机器学习上&#xff0c;作为入门&#xff0c;学了许多机器学习的基础。往后的文章我会穿插着机器学习和深度学习的内容进行&#xff0c;所有有必要在这里先说下两者的关系。 一、从范围上讲 深度学习和机器学习都是人工智能的一个子领域&#xff0c;它…

微信会议活动微展示在线活动报名源码系统 带完整的搭建教程

随着微信的普及&#xff0c;微信会议活动已成为企业、团体和个人进行信息交流、业务推广和品牌宣传的重要平台。然而&#xff0c;如何高效地管理、展示和报名参加这些会议活动&#xff0c;一直是许多组织者面临的难题。下面&#xff0c;小编给大家分享一款微信会议活动微展示在…