微信小程序 --- wx.request网络请求封装

网络请求封装

网络请求模块难度较大,如果学习起来感觉吃力,可以直接学习 [请求封装-使用 npm 包发送请求] 以后的模块

01. 为什么要封装 wx.request

小程序大多数 API 都是异步 API,如 wx.request(),wx.login() 等。这类 API 接口通常都接收一个 Object 对象类型的参数,参数中可以按需指定以下字段来接收接口调用结果:

参数名类型必填说明
successfunction调用成功的回调函数
failfunction调用失败的回调函数
completefunction调用结束的回调函数(调用成功、失败都会执行)
wx.request({// 接口调用成功的回调函数success() {wx.request({success() {wx.request({success() {wx.request({success() {wx.request({success() {wx.request({success() {wx.request({success() {wx.request({success() {}})}})}})}})}})}})}})},// 接口调用失败的回调函数fail() {},// 接口调用结束的回调函数(调用成功、失败都会执行)complete() {}
})

如果采用这种回调函数的方法接收返回的值,可能会出现多层 success 套用的情况,容易出现回调地狱问题,

为了解决这个问题,小程序基础库从 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。

当接口参数 Object 对象中不包含 success/fail/complete 时,将默认返回 promise,否则仍按回调方式执行,无返回值。

但是部分接口如 downloadFile, request, uploadFile 等本身就有返回值,因此不支持 promise 调用方式,它们的 promisify 需要开发者自行封装。

Axios 是我们日常开发中常用的一个基于 promise 的网络请求库

我们可以参考 Axios 的 [使用方式] 来封装自己的网络请求模块,咱们看一下使用的方式:

网络请求模块封装

import WxRequest from 'mina-request'// 自定义配置新建一个实例
const instance = new WxRequest(({baseURL: 'https://some-domain.com/api/',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}
})// 通过 instance.request(config) 方式发起网络请求
instance.requst({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'}
})// 通过 instance.get 方式发起网络请求
instance.get(url, data, config)// 通过 instance.delete 方式发起网络请求
instance.delete(url, data, config)// 通过 instance.post 方式发起网络请求
instance.post(url, data, config)// 通过 instance.put 方式发起网络请求
instance.put(url, data, config)// ----------------------------------------------// 添加请求拦截器
instance.interceptors.request = (config) => {// 在发送请求之前做些什么return config
}// 添加响应拦截器
instance.interceptors.response = (response) => {// response.isSuccess = true,代码执行了 wx.request 的 success 回调函数// response.isSuccess = false,代码执行了 wx.request 的 fail 回调函数// response.statusCode // http 响应状态码// response.config // 网络请求请求参数// response.data 服务器响应的真正数据// 对响应数据做点什么return response
}

封装后网络请求模块包含以下功能

  1. 包含 request 实例方法发送请求
  2. 包含 get、delete、put、post 等实例方法可以快捷的发送网络请求
  3. 包含 请求拦截器、响应拦截器
  4. 包含 uploadFile 将本地资源上传到服务器 API
  5. 包含 all 并发请求方法
  6. 同时优化了并发请求时 loading 显示效果

02. 请求封装-request 方法

思路分析:

在封装网络请求模块的时候,采用 Class 类来进行封装,采用类的方式封装代码更具可复用性,也方便地添加新的方法和属性,提高代码的扩展性

我们先创建一个 class 类,同时定义 constructor 构造函数

// 创建 WxRequest 类
class WxRequest {constructor() {}
}

我们在 WxRequest 类内部封装一个 request 实例方法

request 实例方法中需要使用 Promise 封装 wx.request,也就是使用 Promise 处理 wx.request 的返回结果

request 实例方法接收一个 options 对象作为形参,options 参数和调用 wx.request 时传递的请求配置项一致

  • 接口调用成功时,通过 resolve 返回响应数据
  • 接口调用失败时,通过 reject 返回错误原因
class WxRequest {// 定义 constructor 构造函数,用于创建和初始化类的属性和方法constructor() {}/*** @description 发起请求的方法* @param { Object} options 请求配置选项,同 wx.request 请求配置选项* @returns Promise*/request(options) {// 使用 Promise 封装异步请求return new Promise((resolve, reject) => {// 使用 wx.request 发起请求wx.request({...options,// 接口调用成功的回调函数success: (res) => {resolve(res)},// 接口调用失败的回调函数fail: (err) =>  {reject(err)}})})}
}

然后对 WxRequest 进行实例化,然后测试 request 实例方法是否封装成功!

注意:我们先将类 和 实例化的对象放到同一个文件中,这样方便进行调试,后面我们在拆分成两个文件


class WxRequest {// coding....
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
const instance = new WxRequest()// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

在其他模块中引入封装的文件后,我们期待通过 request() 方式发起请求,以 promise 的方式返回参数

// 导入创建的实例
import instance from '../../utils/wx-request'Page({// 点击按钮触发 handler 方法async handler() {// 通过实例调用 request 方法发送请求const res = await instance.request({url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',method: 'GET'})console.log(res)}
})

落地代码:

➡️ /utils/request.js

// 创建 WxRequest 类,采用类的方式进行封装会让方法更具有复用性,也可以方便进行添加新的属性和方法class WxRequest {// 定义 constructor 构造函数,用于创建和初始化类的属性和方法constructor() {}/*** @description 发起请求的方法* @param { Object} options 请求配置选项,同 wx.request 请求配置选项* @returns Promise*/request(options) {// 使用 Promise 封装异步请求return new Promise((resolve, reject) => {// 使用 wx.request 发起请求wx.request({...options,// 接口调用成功的回调函数success: (res) => {resolve(res)},// 接口调用失败的回调函数fail: (err) => {reject(err)}})})}
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
const instance = new WxRequest()// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

➡️ /pages/test/test.js

import instance from '../../utils/request'Page({// 点击按钮触发 handler 方法async handler() {// 第一种调用方式:通过 then 和 catch 接收返回的值// instance//   .request({//     url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',//     method: 'GET'//   })//   .then((res) => {//     console.log(res)//   })//   .catch((err) => {//     console.log(err)//   })// 第二种调用方式:通过 await 和 async 接收返回的值const res = await instance.request({url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',method: 'GET'})console.log(res)}})

03. 请求封装-设置请求参数

思路分析:

在发起网络请求时,需要配置一些请求参数,

其中有一些参数我们可以设置为默认参数,例如:请求方法、超时时长 等等,因此我们在封装时我们要定义一些默认的参数。

// 默认参数对象
defaults = {baseURL: '', // 请求基准地址url: '', // 开发者服务器接口地址data: null, // 请求参数method: 'GET',// 默认请求方法// 请求头header: {'Content-type': 'application/json' // 设置数据的交互格式},timeout: 60000 // 小程序默认超时时间是 60000,一分钟// 其他参数...
}

但是不同的项目,请求参数的设置是不同的,我们还需要允许在进行实例化的时候,传入参数,对默认的参数进行修改。例如:

// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api', // 请求基准地址timeout: 10000 // 微信小程序 timeout 默认值为 60000
})

在通过实例,调用 request 实例方法时也会传入相关的请求参数

const res = await instance.request({url: '/index/findBanner',method: 'GET'
})

从而得出结论:请求参数的设置有三种方式:

  1. 默认参数:在 WxRequest 类中添加 defaults 实例属性来设置默认值
  2. 实例化时参数:在对 WxRequest 类进行实例化时传入相关的参数,需要在 constructor 构造函数形参进行接收
  3. 调用实例方法时传入请求参数

默认参数和自定义参数的合并操作,通常会在constructor中进行。

因此我们就在 constructor 中将开发者传入的相关参数和defaults 默认值进行合并,需要传入的配置项覆盖默认配置项

class WxRequest {+   // 默认参数对象
+   defaults = {
+     baseURL: '', // 请求基准地址
+     url: '', // 开发者服务器接口地址
+     data: null, // 请求参数
+     method: 'GET',// 默认请求方法
+     // 请求头
+     header: {
+       'Content-type': 'application/json' // 设置数据的交互格式
+     },
+     timeout: 60000 // 小程序默认超时时间是 60000,一分钟
+   }/*** @description 定义 constructor 构造函数,用于创建和初始化类的属性和方法* @param {*} params 用户传入的请求配置项*/
+   constructor(params = {}) {
+     // 在实例化时传入的参数能够被 constructor 进行接收
+     console.log(params)+     // 使用 Object.assign 合并默认参数以及传递的请求参数
+     this.defaults = Object.assign({}, this.defaults, params)
+   }// coding....
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
+ const instance = new WxRequest({
+   baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
+   timeout: 15000
+ })// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

在调用 request 实例时也会传入相关的参数,是发起请求真正的参数,

我们需要将调用 reqeust 实例方法时传入的参数,继续覆盖合并以后的参数,请求才能够发送成功

注意:让使用传入的参数覆盖默认的参数,同时拼接完整的请求地址。

// 创建 request 请求方法
request(options) {
+  // 拼接完整的请求地址
+  options.url = this.defaults.baseURL + options.url
+  // 合并请求参数
+  options = { ...this.defaults, ...options }return new Promise((resolve, reject) => {// coding...})}

落地代码:

➡️ utils/request.js

// 创建 Request 类,用于封装 wx.request() 方法
class WxRequest {+   // 默认参数对象
+   defaults = {
+     baseURL: '', // 请求基准地址
+     url: '', // 开发者服务器接口地址
+     data: null, // 请求参数
+     method: 'GET',// 默认请求方法
+     // 请求头
+     header: {
+       'Content-type': 'application/json' // 设置数据的交互格式
+     },
+     timeout: 60000 // 小程序默认超时时间是 60000,一分钟
+   }+   /**
+    * @description 定义 constructor 构造函数,用于创建和初始化类的属性和方法
+    * @param {*} params 用户传入的请求配置项
+    */
+   constructor(params = {}) {
+     // 在实例化时传入的参数能够被 constructor 进行接收
+     console.log(params)+     // 使用 Object.assign 合并默认参数以及传递的请求参数
+     this.defaults = Object.assign({}, this.defaults, params)
+   }/*** @description 发起请求的方法* @param { Object} options 请求配置选项,同 wx.request 请求配置选项* @returns Promise*/request(options) {
+    // 拼接完整的请求地址
+    options.url = this.defaults.baseURL + options.url
+    // 合并请求参数
+    options = { ...this.defaults, ...options }// 方法返回一个 Promise 对象return new Promise((resolve, reject) => {// coding...})}
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 15000
})// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

04. 请求封装-封装请求快捷方法

思路分析:

目前已经完成了 request() 请求方法的封装,同时处理了请求参数。

每次发送请求时都使用 request() 方法即可,但是项目中的接口地址有很多,不是很简洁

const res = await instance.request({url: '/index/findBanner',method: 'GET'
})

所以我们在 request() 基础上封装一些快捷方法,简化 request() 的调用。

需要封装 4 个快捷方法,分别是 getdeletepostput,他们的调用方式如下:

instance.get('请求地址', '请求参数', '请求配置')
instance.delete('请求地址', '请求参数', '请求配置')
instance.post('请求地址', '请求参数', '请求配置')
instance.put('请求地址', '请求参数', '请求配置')

这 4 个请求方法,都是通过实例化的方式进行调用,所以需要 Request 类中暴露出来 getdeletepostput 方法。每个方法接收三个参数,分别是:接口地址、请求参数以及其他参数。

这 4 个快捷方法,本质上其实还是调用 request 方法,我们只要在方法内部组织好参数,调用 request 发送请求即可

class WxRequest {// coding...+   // 封装 GET 实例方法
+   get(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'GET' }, config))
+   }+   // 封装 POST 实例方法
+   post(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'POST' }, config))
+   }+   // 封装 PUT 实例方法
+   put(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'PUT' }, config))
+   }+   // 封装 DELETE 实例方法
+   delete(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
+   }
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 15000
})// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

落地代码:

➡️ utils/request.js

class WxRequest {// coding...+   // 封装 GET 实例方法
+   get(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'GET' }, config))
+   }+   // 封装 POST 实例方法
+   post(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'POST' }, config))
+   }+   // 封装 PUT 实例方法
+   put(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'PUT' }, config))
+   }+   // 封装 DELETE 实例方法
+   delete(url, data = {}, config = {}) {
+     return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
+   }
}// ----------------- 实例化 ----------------------// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 15000
})// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

➡️ /pages/test/test.js

// 导入创建的实例
import instance from '../../utils/wx-request'Page({async handler() {// 第一种调用方式:通过 then 和 catch 接收返回的值// instance//   .request({//     url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',//     method: 'GET'//   })//   .then((res) => {//     console.log(res)//   })//   .catch((err) => {//     console.log(err)//   })// 第二种调用方式// 通过实例调用 request 方法发送请求// const res = await instance.request({//   url: '/index/findBanner',//   method: 'GET'// })// console.log(res)// 第三种调用方式:通过调用快捷方式接收返回的值const res = await instance.get('/index/findBanner')console.log(res)}
})

05. 请求封装-wx.request 注意事项

知识点:

在使用 wx.request 发送网络请求时。

只要成功接收到服务器返回,无论statusCode是多少,都会进入 success 回调

开发者根据业务逻辑对返回值进行判断。

什么时候会有 fail 回调函数 ?

一般只有网络出现异常、请求超时等时候,才会走 fail 回调

在这里插入图片描述

落地代码:

测试代码

request() {wx.request({url: 'https://gmall-prod.atguigu.cn/mall-api/index/findCategory',method: 'GET',// timeout: 100, 测试网络超时,需要调整网络success: (res) => {console.log('只要成功接收到服务器返回,不管状态是多少,都会进入 success 回调')console.log(res)},fail: (err) => {console.log(err)}})
}

06. 请求封装-定义请求/响应拦截器

思路分析:

为了方便统一处理请求参数以及服务器响应结果,为 WxRequest 添加拦截器功能,拦截器包括 请求拦截器响应拦截器

请求拦截器本质上是在请求之前调用的函数,用来对请求参数进行新增和修改

响应拦截器本质上是在响应之后调用的函数,用来对响应数据做点什么

注意:不管成功响应还是失败响应,都会执行响应拦截器

拦截器的使用方式:

// 请求拦截器
instance.interceptors.request = (config) => {// 在发送请求之前做些什么return config
}// 响应拦截器
instance.interceptors.response = (response) => {// 对响应数据做点什么return response
}

通过使用方式,我们可以得出结论:

可以在 WxRequest 类内部定义 interceptors 实例属性,属性中需要包含 request 以及 response 方法

需要注意:在发送请求时,还需要区分是否通过实例调用了拦截器:

  1. 没有通过实例调用拦截器,需要定义默认拦截器,在默认拦截器中,需要将请求参数进行返回
  2. 通过实例调用拦截器,那么实例调用的拦截器会覆盖默认的拦截器方法,然后将新增或修改的请求参数进行返回

实现拦截器的思路:

  1. WxRequest 类内部定义 interceptors 实例属性,属性中需要包含 request 以及 response 方法
  2. 是否通过实例调用了拦截器
    • 是:定义默认拦截器
    • 否:实例调用的拦截器覆盖默认拦截器
  3. 在发送请求之前,调用请求拦截器
  4. 在服务器响应以后,调用响应拦截器
    • 不管成功、失败响应,都需要调用响应拦截器

WxRequest 类内部定义 interceptors 实例属性,属性中需要包含 request 以及 response 方法。

没有使用拦截器,定义默认拦截器,需要将默认的请求参数进行返回。

如果使用了拦截器,那么使用者的拦截器会覆盖默认的拦截器方法

class WxRequest {// coding...+   // 定义拦截器对象,包含请求拦截器和响应拦截器方法,方便在请求或响应之前进行处理。
+   interceptors = {
+     // 请求拦截器
+     request: (config) => config,
+     // 响应拦截器
+     response: (response) => response
+   }// 用于创建和初始化类的属性以及方法// 在实例化时传入的参数,会被 constructor 形参进行接收constructor(options = {}) {// coding...}
}
// ----------------- 以下是实例化的代码 --------------------
// 目前写到同一个文件中,是为了方便进行测试,以后会提取成多个文件// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 15000
})+ // 配置请求拦截器
+ instance.interceptors.request = (config) => {
+   // 在发送请求之前做些什么
+   return config
+ }+ // 响应拦截器
+ instance.interceptors.response = (response) => {
+   // 对响应数据做点什么
+   return response
+ }// 将 WxRequest 实例进行暴露出去,方便在其他文件中进行使用
export default instance

在发送请求之前,调用请求拦截器,在服务器响应以后,调用响应拦截器

不管成功、失败,都需要调用响应拦截器

class WxRequest {// coding...// request 实例方法接收一个对象类型的参数// 属性值和 wx.request 方法调用时传递的参数保持一致request(options) {// 注意:需要先合并完整的请求地址 (baseURL + url)// https://gmall-prod.atguigu.cn/mall-api/index/findBanneroptions.url = this.defaults.baseURL + options.url// 合并请求参数options = { ...this.defaults, ...options }+     // 在发送请求之前调用请求拦截器
+     options = this.interceptors.request(options)// 需要使用 Promise 封装 wx.request,处理异步请求return new Promise((resolve, reject) => {wx.request({...options,// 当接口调用成功时会触发 success 回调函数success: (res) => {
+           // 不管接口成功还是失败,都需要调用响应拦截器
+           // 第一个参数:需要合并的目标对象
+           // 第二个参数:服务器响应的数据
+           // 第三个参数:请求配置以及自定义的属性
+           const mergetRes = Object.assign({}, res, { config: options })
+           resolve(this.interceptors.response(mergetRes))},// 当接口调用失败时会触发 fail 回调函数fail: (err) => {
+           // 不管接口成功还是失败,都需要调用响应拦截器
+            const mergetErr = Object.assign({}, err, { config: options })
+            reject(this.interceptors.response(mergetErr))}})})}// coding...
}

落地代码:

➡️ utils/request.js

// 创建 WxRequest 类
// 通过类的方式来进行封装,会让代码更加具有复用性
// 也可以方便添加新的属性和方法class WxRequest {// 定义实例属性,用来设置默认请求参数defaults = {baseURL: '', // 请求基准地址url: '', // 接口的请求路径data: null, // 请求参数method: 'GET', // 默认的请求方法// 请求头header: {'Content-type': 'application/json' // 设置数据的交互格式},timeout: 60000 // 默认的超时时长,小程序默认的超时时长是 1 分钟}+   // 定义拦截器对象,包含请求拦截器和响应拦截器方法,方便在请求或响应之前进行处理。
+   interceptors = {
+     // 请求拦截器
+     request: (config) => config,
+     // 响应拦截器
+     response: (response) => response
+   }// 用于创建和初始化类的属性以及方法// 在实例化时传入的参数,会被 constructor 形参进行接收constructor(params = {}) {// 通过 Object.assign 方法合并请求参数// 注意:需要传入的参数,覆盖默认的参数,因此传入的参数需要放到最后this.defaults = Object.assign({}, this.defaults, params)}// request 实例方法接收一个对象类型的参数// 属性值和 wx.request 方法调用时传递的参数保持一致request(options) {// 注意:需要先合并完整的请求地址 (baseURL + url)// https://gmall-prod.atguigu.cn/mall-api/index/findBanneroptions.url = this.defaults.baseURL + options.url// 合并请求参数options = { ...this.defaults, ...options }+     // 在发送请求之前调用请求拦截器
+     options = this.interceptors.request(options)// 需要使用 Promise 封装 wx.request,处理异步请求return new Promise((resolve, reject) => {wx.request({...options,// 当接口调用成功时会触发 success 回调函数success: (res) => {
+           // 不管接口成功还是失败,都需要调用响应拦截器
+           // 第一个参数:需要合并的目标对象
+           // 第二个参数:服务器响应的数据
+           // 第三个参数:请求配置以及自定义的属性
+           const mergeRes = Object.assign({}, res, { config: options })
+           resolve(this.interceptors.response(mergeRes))},// 当接口调用失败时会触发 fail 回调函数fail: (err) => {
+           // 不管接口成功还是失败,都需要调用响应拦截器
+           const mergeErr = Object.assign({}, err, { iconfig: options })
+           // 不管接口成功还是失败,都需要调用响应拦截器
+           err = this.interceptors.response(mergeErr)
+           reject(err)}})})}// 封装 GET 实例方法get(url, data = {}, config = {}) {// 需要调用 request 请求方法发送请求,只需要组织好参数,传递给 request 请求方法即可// 当调用 get 方法时,需要将 request 方法的返回值 return 出去return this.request(Object.assign({ url, data, method: 'GET' }, config))}// 封装 DELETE 实例方法delete(url, data = {}, config = {}) {return this.request(Object.assign({ url, data, method: 'DELETE' }, config))}// 封装 POST 实例方法post(url, data = {}, config = {}) {return this.request(Object.assign({ url, data, method: 'POST' }, config))}// 封装 PUT 实例方法put(url, data = {}, config = {}) {return this.request(Object.assign({ url, data, method: 'PUT' }, config))}
}// ----------------- 以下是实例化的代码 --------------------
// 目前写到同一个文件中,是为了方便进行测试,以后会提取成多个文件// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 15000
})+ // 配置请求拦截器
+ instance.interceptors.request = (config) => {
+   // 在发送请求之前做些什么
+   return config
+ }+ // 响应拦截器
+ instance.interceptors.response = (response) => {
+ 
+   // 对响应数据做点什么
+   return response.data
+ }// 将 WxRequest 实例进行暴露出去,方便在其他文件中进行使用
export default instance

07. 请求封装-完善请求/响应拦截器

思路分析:

在响应拦截器,我们需要判断是请求成功,还是请求失败,然后进行不同的业务逻辑处理。

例如:请求成功以后将数据简化返回,网络出现异常则给用户进行网络异常提示。

目前不管请求成功 (success),还是请求失败(fail),都会执行响应拦截器

那么怎么判断是请求成功,还是请求失败呢 ?

封装需求:

  1. 如果请求成功,将响应成功的数据传递给响应拦截器,同时在传递的数据中新增 isSuccess: true 字段,表示请求成功
  2. 如果请求失败,将响应失败的数据传递给响应拦截器,同时在传递的数据中新增 isSuccess: false 字段,表示请求失败

在实例调用的响应拦截中,根据传递的数据进行以下的处理:

  • 如果isSuccess: true 表示服务器响应了结果,我们可以将服务器响应的数据简化以后进行返回
  • 如果isSuccess: false 表示是网络超时或其他网络问题,提示 网络异常,同时将返回即可

落地代码:

➡️ utils/request.js


class WxRequest {// coding....request(options) {// coding....// 使用 Promise 封装异步请求return new Promise((resolve, reject) => {// 使用 wx.request 发起请求wx.request({...options,// 接口调用成功的回调函数success: (res) => {// 响应成功以后触发响应拦截器if (this.interceptors.response) {
+             // 调用响应拦截器方法,获取到响应拦截器内部返回数据
+             // success: true 表示服务器成功响应了结果,我们需要对业务状态码进行判断
+             res = this.interceptors.response({ response: res, isSuccess: true })}// 将数据通过 resolve 进行返回即可resolve(res)},// 接口调用失败的回调函数fail: (err) => {// 响应失败以后也要执行响应拦截器if (this.interceptors.response) {
+             // isSuccess: false 表示是网络超时或其他问题
+             err = this.interceptors.response({ response: err, isSuccess: true })}// 当请求失败以后,通过 reject 返回错误原因reject(err)}})})}// coding......
}// -----------------------------------------------------// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api'
})// 设置请求拦截器
instance.setRequestInterceptor((config) => {console.log('执行请求拦截器')return config
})// 设置响应拦截器
+ instance.setResponseInterceptor((response) => {
+   const { response: res, isSuccess } = response+   // isSuccess: false 表示是网络超时或其他问题,提示 网络异常,同时将返回即可
+   if (!isSuccess) {
+     wx.toast('网络异常,请稍后重试~')
+     // 如果请求错误,将错误的结果返回出去
+     return res
+   }+  // 简化数据
+  return response.data
})// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

08. 请求封装-使用请求/响应拦截器

思路分析:

使用请求拦截器:

在发送请求时,购物车列表、收货地址、更新头像等接口,都需要进行权限验证,因此我们需要在请求拦截器中判断本地是否存在访问令牌 token ,如果存在就需要在请求头中添加 token 字段。

使用响应拦截器:

在使用 wx.request 发送网络请求时。只要成功接收到服务器返回,无论statusCode是多少,都会进入 success 回调。

因此开发者根据业务逻辑对返回值进行判断。

后端返回的业务状态码如下:

  1. 业务状态码 === 200, 说明接口请求成功,服务器成功返回了数据
  2. 业务状态码 === 208, 说明没有 token 或者 token 过期失效,需要登录或者重新登录
  3. 业务状态码 === 其他,说明请求或者响应出现了异常

其他测试接口:/cart/getCartList

落地代码:

➡️ utils/request.js

// 创建 WxRequest 类,采用类的方式进行封装会让方法更具有复用性,也可以方便进行添加新的属性和方法class WxRequest {// coding...
}// -----------------------------------------------------// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',timeout: 5000
})// 设置请求拦截器
instance.setRequestInterceptor((config) => {
+   // 从本地获取 token
+   if (wx.getStorageSync('token')) {
+     // 如果存在 token ,则添加请求头
+     config.header['token'] = wx.getStorageSync('token')
+   }
+ 
+   // 返回请求参数
+   return config
})// 设置响应拦截器
instance.setResponseInterceptor(async (response) => {
+   const { response: res, isSuccess } = response+   // isSuccess: false 表示是网络超时或其他问题,提示 网络异常,同时将返回即可
+   if (!isSuccess) {
+     wx.toast('网络异常,请稍后重试~')
+     // 如果请求错误,将错误的结果返回出去
+     return res
+   }+   switch (res.data.code) {
+     case 200:
+       return res.data+     case 208:
+       // 判断用户是否点击了确定
+       const modalStatus = await wx.modal({
+         title: '提示',
+         content: '登录授权过期,请重新授权'
+       })+       // 如果点击了确定,先清空本地的 token,然后跳转到登录页面
+       if (modalStatus) {
+         wx.clearStorageSync()
+         wx.navigateTo({
+           url: '/pages/login/login'
+         })
+       }
+       return+     default:
+       wx.showToast({
+         title: '接口调用失败~~~~',
+         icon: 'none'
+       })+       // 将错误继续向下传递
+       return Promise.reject(response)
+   }
})// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

09. 请求封装-添加并发请求

思路分析:

前端并发请求是指在前端页面同时向后端发起多个请求的情况。当一个页面需要请求多个接口获取数据时,为了提高页面的加载速度和用户体验,可以同时发起多个请求,这些请求之间就是并发的关系。

我们通过两种方式演示发起多个请求:

  1. 使用 asyncawait 方式
  2. 使用 Promise.all() 方式

首先使用asyncawait 方式发送请求,使用 asyncawait 能够控制异步任务以同步的流程执行,代码如下,这时候就会产生一个问题,当第一个请求执行完以后,才能执行第二个请求,这样就会造成请求的阻塞,影响渲染的速度,如下图

在这里插入图片描述

这时候我们需要使用 Promise.all() 方式同时发起多个异步请求,并在所有请求完成后再进行数据处理和渲染。使用Promise.all() 能够将多个请求同时发出,不会造成请求的阻塞。

在这里插入图片描述

通过两种方式演示,我们能够知道封装并发请求的必要性。在 WxRequest 实例中封装 all 方法,使用展开运算符将传入的参数转成数组,方法的内部,使用 Promise.all() 接收传递的多个异步请求,将处理的结果返回即可。

class WxRequest {// coding...+   // 封装处理并发请求的 all 方法
+   all(...promise) {
+     return Promise.all(promise)
+   }// coding...
}// coding...

在这里插入图片描述

落地代码:

➡️ utils/request.js

class WxRequest {// coding...+   // 封装处理并发请求的 all 方法
+   all(...promise) {
+     return Promise.all(promise)
+   }// coding...
}// coding...

➡️ /pages/test/test.js

import instance from '../../utils/http'Page({async getData() {// 使用 Promise.all 同时处理多个异步请求const [res1, res2] = await instance.all([instance.get('/mall-api/index/findBanner'),instance.get('/mall-api/index/findCategory1')])console.log(res1)console.log(res2)}
})

10. 请求封装-添加 loading

思路分析:

在封装时添加 loading 效果,从而提高用户使用体验

  1. 在请求发送之前,需要通过 wx.showLoading 展示 loading 效果

  2. 当服务器响应数据以后,需要调用 wx.hideLoading 隐藏 loading 效果

要不要加 loading 添加到 WxRequest 内部 ?

  1. 在类内部进行添加,方便多个项目直接使用类提供的 loading 效果,也方便统一优化 wx.showLoading 使用体验。

    但是不方便自己来进行 loading 个性化定制。

  2. 如果想自己来控制 loading 效果,带来更丰富的交互体验,就不需要将 loading 封装到类内部,但是需要开发者自己来优化 wx.showLoading 使用体验,每个项目都要写一份。

大伙可以按照自己的业务需求进行封装,

在项目中我们会选择第一种方式。折中

不过也会通过属性控制是否展示 loading,从而方便类使用者自己控制 loading 显示

落地代码:

➡️ utils/request.js


class WxRequest {// coding...constructor(options = {}) {// coding...}// 创建 request 请求方法request(options) {// 拼接完整的请求地址options.url = this.defaults.baseURL + options.url// 合并请求参数options = { ...this.defaults, ...options }+     // 发送请求之前添加 loding
+     wx.showLoading()// 如果存在请求拦截器,我们则调用请求拦截器if (this.interceptors.request) {// 请求之前,触发请求拦截器options = this.interceptors.request(options)}// 方法返回一个 Promise 对象return new Promise((resolve, reject) => {wx.request({...options,success: (res) => {// coding...},fail: (err) => {// coding...},
+         complete: () => {
+           // 接口调用完成后隐藏 loding
+           wx.hideLoading()
+         }})})}// coding...
}

11. 请求封装-完善 loading

思路分析:

目前在发送请求时,请求发送之前会展示 loading,响应以后会隐藏 loading

但是 loading 的展示和隐藏会存在以下问题:

  1. 每次请求都会执行 wx.showLoading(),但是页面中只会显示一个,后面的 loading会将前面的覆盖
  2. 同时发起多次请求,只要有一个请求成功响应就会调用 wx.hideLoading,导致其他请求还没完成,也不会 loading
  3. 请求过快 或 一个请求在另一个请求后立即触发,这时候会出现 loading 闪烁问题

我们通过 队列 的方式解决这三个问题:首先在类中新增一个实例属性 queue,初始值是一个空数组

  1. 发起请求之前,判断 queue 如果是空数组则显示 loading ,然后立即向queue新增请求标识
  2. complete 中每次请求成功结束,从 queue 中移除一个请求标识,queue 为空时隐藏 loading
  3. 为了解决网络请求过快产生loading 闪烁问题,可以使用定时器来做判断即可

落地代码:

➡️ utils/request.js


class WxRequest {// coding...constructor(options = {}) {// 使用 Object.assign 合并默认参数以及传递的请求参数this.defaults = Object.assign({}, this.defaults, options)// 定义拦截器对象,包含请求拦截器和响应拦截器方法,方便在请求或响应之前进行处理。this.interceptors = {// 请求拦截器request: null,// 响应拦截器response: null}+     // 初始化 queue 数组,用于存储请求队列
+     this.queue = []}// 创建 request 请求方法request(options) {
+     // 如果有新的请求,则清空上一次的定时器
+     this.timerId && clearTimeout(this.timerId)// 拼接完整的请求地址options.url = this.defaults.baseURL + options.url// 合并请求参数options = { ...this.defaults, ...options }// 如果存在请求拦截器,我们则调用请求拦截器if (this.interceptors.request) {// 请求之前,触发请求拦截器options = this.interceptors.request(options)}+     // 发送请求之前添加 loding
+     this.queue.length === 0 && wx.showLoading()
+     // 然后想队列中添加 request 标识,代表需要发送一次新请求
+     this.queue.push('request')// 方法返回一个 Promise 对象return new Promise((resolve, reject) => {wx.request({...options,success: (res) => {// coding...},fail: (err) => {// coding...},complete: () => {// 接口调用完成后隐藏 loding// wx.hideLoading()+           // 每次请求结束后,从队列中删除一个请求标识
+           this.queue.pop()
+ 
+           // 如果队列已经清空,在往队列中添加一个标识
+           this.queue.length === 0 && this.queue.push('request')+           // 等所有的任务执行完以后,经过 100 毫秒
+           // 将最后一个 request 清除,然后隐藏 loading
+           this.timerId = setTimeout(() => {
+             this.queue.pop()
+             this.queue.length === 0 && wx.hideLoading()
+           }, 100)}})})}// 封装快捷请求方法// coding...// 封装拦截器// coding...
}// coding...export default instance

12. 请求封装-控制 loading 显示

思路分析:

在我们封装的网络请求文件中,通过 wx.showLoading 默认显示了 loading 效果

但是在实际开发中,有的接口可能不需要显示 loading 效果,或者开发者希望自己来控制 loading 的样式与交互,那么就需要关闭默认 loading 效果。

这时候我们就需要一个开关来控制 loading 显示。

  1. 类内部设置默认请求参数 isLoading 属性,默认值是 true,在类内部根据 isLoading 属性做判断即可
  2. 某个接口不需要显示 loading 效果,可以在发送请求的时候,可以新增请求配置 isLoading 设置为 false
  3. 整个项目都不需要显示loading 效果,可以在实例化的时候,传入 isLoading 配置为 false

实现步骤:

  1. 在 WxRequest 类的默认请求配置项中,设置 isLoading 默认值为 true,显示 loading

    class WxRequest {// 初始化默认的请求属性defaults = {url: '', // 开发者服务器接口地址data: null, // 请求参数header: {}, // 设置请求的 headertimeout: 60000, // 超时时间method: 'GET', // 请求方式
    +    isLoading: true // 是否显示 loading 提示框}// code...
    }
    
  2. 在进行实例化的时候,可以配置 isLoading 配置为 false,隐藏 loading

    // 对 WxRequest 进行实例化
    const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
    +   isLoading: false // 隐藏 loading
    })
    
  3. 在发送网络请求时候,传入请求配置 isLoading 配置为 false,隐藏 loading

    async func() {
    +  // 请求配置 isLoading 配置为 false,隐藏 loading
    +  await instance.get('/index/findCategory1', null, { isLoading: true })
    }
    
  4. wx-request 内部代码实现

    // 创建 WxRequest 类,采用类的方式进行封装会让方法更具有复用性,也可以方便进行添加新的属性和方法class WxRequest {// 初始化默认的请求属性defaults = {url: '', // 开发者服务器接口地址data: null, // 请求参数header: {}, // 设置请求的 headertimeout: 60000, // 超时时间method: 'GET', // 请求方式
    +     isLoading: true // 是否显示 loading 提示框}constructor(params = {}) {// coding...}request(options) {// coding...+     // 发送请求之前添加 loding
    +     if (options.isLoading) {
    +       this.queue.length === 0 && wx.showLoading()
    +       // 然后想队列中添加 request 标识,代表需要发送一次新请求
    +       this.queue.push('request')
    +     }// 请求之前,触发请求拦截器// 如果存在请求拦截器,则触发请求拦截器if (this.interceptors.request) {options = this.interceptors.request(options)}// 使用 Promise 封装异步请求return new Promise((resolve, reject) => {// 使用 wx.request 发起请求wx.request({...options,// 接口调用成功的回调函数success: (res) => {// coding...},// 接口调用失败的回调函数fail: (err) => {// coding...},complete: () => {// 接口调用完成后隐藏 loding// wx.hideLoading()+          if (!options.isLoading) return// 每次请求结束后,从队列中删除一个请求标识this.queue.pop()// 如果队列已经清空,在往队列中添加一个标识this.queue.length === 0 && this.queue.push('request')// 等所有的任务执行完以后,经过 100 毫秒// 将最后一个 request 清除,然后隐藏 loadingthis.timerId = setTimeout(() => {this.queue.pop()this.queue.length === 0 && wx.hideLoading()}, 100)}})})}// coding...
    }

13. 请求封装-封装 uploadFile

思路分析:

wx.uploadFile 也是我们在开发中常用的一个 API,用来将本地资源上传到服务器。

例如:在获取到微信头像以后,将微信头像上传到公司服务器。

wx.uploadFile({url: '', // 必填项,开发者服务器地址filePath: '', // 必填项,要上传文件资源的路径 (本地路径)name: '' // 必填项,文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
})

在了解了 API 以后,我们直接对 wx.uploadFile 进行封装即可。

首先在 WxRequest 类内部创建 upload 实例方法,实例方法接收四个属性:


/**
* @description 文件上传接口封装
* @param { string } url 文件上传地址
* @param { string } filePath 要上传文件资源的路径
* @param { string } name 文件对应的 key
* @param { string } config 其他配置项
* @returns 
*/
upload(url, filePath, name, config = {}) {return this.request(Object.assign({ url, filePath, name, method: 'UPLOAD' }, config))
}

这时候我们需要在 request 实例方法中,对 method 进行判断,如果是 UPLOAD,则调用 wx.uploadFile 上传API

// request 实例方法接收一个对象类型的参数
// 属性值和 wx.request 方法调用时传递的参数保持一致
request(options) {// coding...// 需要使用 Promise 封装 wx.request,处理异步请求return new Promise((resolve, reject) => {
+     if (options.method === 'UPLOAD') {
+       wx.uploadFile({
+         ...options,
+ 
+         success: (res) => {
+           // 将服务器响应的数据通过 JSON.parse 转换为 JS 对象
+           res.data = JSON.parse(res.data)
+ 
+           const mergeRes = Object.assign({}, res, {
+             config: options,
+             isSuccess: true
+           })
+ 
+           resolve(this.interceptors.response(mergeRes))
+         },
+ 
+         fail: (err) => {
+           const mergeErr = Object.assign({}, err, {
+             config: options,
+             isSuccess: true
+           })
+ 
+           reject(this.interceptors.response(mergeErr))
+         },
+ 
+         complete: () => {
+           this.queue.pop()
+ 
+           this.queue.length === 0 && wx.hideLoading()
+         }
+       })} else {wx.request({// coding...})}})
}

落地代码:

➡️ utils/request.js

// request 实例方法接收一个对象类型的参数
// 属性值和 wx.request 方法调用时传递的参数保持一致
request(options) {// coding...// 需要使用 Promise 封装 wx.request,处理异步请求return new Promise((resolve, reject) => {
+     if (options.method === 'UPLOAD') {
+       wx.uploadFile({
+         ...options,
+ 
+         success: (res) => {
+           // 将服务器响应的数据通过 JSON.parse 转换为 JS 对象
+           res.data = JSON.parse(res.data)
+ 
+           const mergeRes = Object.assign({}, res, {
+             config: options,
+             isSuccess: true
+           })
+ 
+           resolve(this.interceptors.response(mergeRes))
+         },
+ 
+         fail: (err) => {
+           const mergeErr = Object.assign({}, err, {
+             config: options,
+             isSuccess: true
+           })
+ 
+           reject(this.interceptors.response(mergeErr))
+         },
+ 
+         complete: () => {
+           this.queue.pop()
+ 
+           this.queue.length === 0 && wx.hideLoading()
+         }
+       })} else {wx.request({// coding...})}})
}

test/test.js

Page({/*** 页面的初始数据*/data: {avatarUrl: '../../assets/Jerry.png'},// 获取微信头像async chooseavatar(event) {// 目前获取的微信头像是临时路径// 临时路径是有失效时间的,在实际开发中,需要将临时路径上传到公司的服务器const { avatarUrl } = event.detail// 调用  upload 方法发送请求,将临时路径上传到公司的服务器const res = await instance.upload('/fileUpload',event.detail.avatarUrl,'file')// 将返回的数据赋值给 data 中的数据this.setData({avatarUrl: res.data})},// coding...
}

14. 请求封装-使用 npm 包发送请求

思路分析:

封装的网络请求模块发布到了 npm ,如果你在学习网络请求模块封装时感觉比较吃力,可以先使用 npm 包实现功能。

npm install mina-request

📌 构建 npm:

​ 安装包后,需要在微信开发者工具中进行 npm 构建,点击 工具 ➡️ 构建 npm

其余步骤参考文档进行开发即可:

mina-request 地址

落地代码:

import WxRequest from "./request";
import { env } from "./env ";
// 是否显示重新登录
let isRelogin = { show: false };
// ----------------- 实例化 ----------------------
// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: env.baseURL,timeout: 15000,
});// 配置请求拦截器
instance.interceptors.request = (config) => {// 在发送请求之前做些什么console.log(config, "在发送请求之前做些什么");// 从本地获取 tokenif (wx.getStorageSync("token")) {// 如果存在 token ,则添加请求头config.header["token"] = wx.getStorageSync("token");}// 返回请求参数return config;
};// 响应拦截器
instance.interceptors.response = (response) => {console.log(response, "响应拦截器");const { isSuccess, data } = response;// isSuccess: false 表示是网络超时或其他问题,提示 网络异常,同时将返回即可if (!isSuccess) {wx.showToast({title: '"网络异常,请稍后重试~"',icon: "error",});// 如果请求错误,将错误的结果返回出去return response;}switch (data.code) {case 200:return data;case 208:// 控制多个接口触发,弹框只出现一次if (!isRelogin.show) {isRelogin.show = true;wx.showModal({showCancel: false,title: "提示",content: "登录授权过期,请重新授权",complete: (res) => {console.log(res);// 清空tokenwx.removeStorageSync("token");//  返回首页wx.reLaunch({url: "/pages/login/login",});// 点击确认后恢复状态isRelogin.show = false;},});}// 将错误继续向下传递return Promise.reject(response);default:wx.showToast({title: "接口调用失败~~~~",icon: "none",});// 将错误继续向下传递return Promise.reject(response);}
};// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance;

15. 环境变量-小程序设置环境变量

知识点:

在实际开发中,不同的开发环境,调用的接口地址是不一样的。

例如:开发环境需要调用开发版的接口地址,生产环境需要调用正式版的接口地址

这时候,我们就可以使用小程序提供了 wx.getAccountInfoSync() 接口,用来获取当前账号信息,在账号信息中包含着 小程序 当前环境版本。

环境版本合法值
开发版develop
体验版trial
正式版release

落地代码:

// 获取当前帐号信息
const accountInfo = wx.getAccountInfoSync()// 获取小程序项目的 appId
console.log(accountInfo.miniProgram.appId)
// 获取小程序 当前环境版本
console.log(accountInfo.miniProgram.envVersion)

根据环境的不同,我们给 env 变量设置不同的请求基准路径 baseURL 然后将 env环境变量导出

// 获取 小程序帐号信息
const { miniProgram } = wx.getAccountInfoSync();// 获取小程序当前开发环境
// develop 开发版, trial 体验版, release 正式版
const { envVersion } = miniProgram;let env = {baseURL: "https://gmall-prod.atguigu.cn/mall-api",
};switch (envVersion) {case "develop":env.baseURL = "https://gmall-prod.atguigu.cn/mall-api";break;case "trial":env.baseURL = "https://gmall-prod.atguigu.cn/mall-api";break;case "release":env.baseURL = "https://gmall-prod.atguigu.cn/mall-api";break;default:console.log("当前环境异常");env.baseURL = "https://gmall-prod.atguigu.cn/mall-api";
}export { env };

16. 接口调用方式说明

思路分析:

在开发中,我们会将所有的网络请求方法放置在 api 目录下统一管理,然后按照模块功能来划分成对应的文件,在文件中将接口封装成一个个方法单独导出,例如:

// 导入封装的网络请求工具 http.js
import http from '../utils/http'/*** @description 获取轮播图数据* @returns Promise*/
export const reqBannerData = () => http.get('/index/findBanner')

这样做的有以下几点好处:

  1. 易于维护:一个文件就是一个模块,一个方法就是一个功能,清晰明了,查找方便
  2. 便于复用:哪里使用,哪里导入,可以在任何一个业务组件中导入需要的方法
  3. 团队合作:分工合作

落地代码:

// 导入封装的网络请求工具 http.js
import http from '../utils/http'/*** @description 获取轮播图数据* @returns Promise*/
export const reqSwiperData = () => http.get('/mall-api/index/findBanner')
// 导入接口 API
import { reqSwiperData } from '../../api/index'Page({// 页面数据data: {swiperList: []},// 小程序页面加载时执行onLoad () {// 调用获取首页数据的方法getHomeList()}// 获取首页数据async getHomeList() {// 获取轮播图数据const res = await reqSwiperData()console.log(res)}
})

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

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

相关文章

【精选】Java面向对象进阶——内部类

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 …

【操作系统】磁盘文件管理系统

实验六 磁盘文件管理的模拟实现 实验目的 文件系统是操作系统中用来存储和管理信息的机构,具有按名存取的功能,不仅能方便用户对信息的使用,也有效提高了信息的安全性。本实验模拟文件系统的目录结构,并在此基础上实现文件的各种…

FISCO BCOS(十七)利用脚本进行区块链系统监控

要利用脚本进行区块链系统监控,你可以使用各种编程语言编写脚本,如Python、Shell等 利用脚本进行区块链系统监控可以提高系统的稳定性、可靠性,并帮助及时发现和解决潜在问题,从而确保区块链网络的正常运行。本文可以利用脚本来解…

Vue3 使用动态组件 component

component 标签&#xff1a;用于动态渲染标签或组件。 语法格式&#xff1a; <component is"标签或组件名">标签内容</component> 动态渲染标签&#xff1a; <template><h3>我是父组件</h3><component is"h1">动态…

SpringCloud(15)之SpringCloud Gateway

一、Spring Cloud Gateway介绍 Spring Cloud Gateway 是Spring Cloud团队的一个全新项目&#xff0c;基于Spring 5.0、SpringBoot2.0、 Project Reactor 等技术开发的网关。旨在为微服务架构提供一种简单有效统一的API路由管理方式。 Spring Cloud Gateway 作为SpringCloud生态…

【Unity】MySql +Navicat 安装教程

问题描述 在使用Unity开发的时候&#xff0c;有的时候我们是需要使用Mysql数据库的&#xff0c;本教程使用的MySql 和Navicat均为免安装版 ❶mysql安装 1.下载mysql解压至任意目录&#xff0c;此处以“C:\mysql-5.6.39-winx64”为例. mysql百度云连接&#xff1a; 链接&…

Java的递归【详解】

1.认识递归基础知识 什么是方法递归&#xff1f; 递归是一种算法&#xff0c;在程序设计语言中广泛应用。 从形式上说&#xff1a;方法调用自身的形式称为方法递归&#xff08; recursion&#xff09;。 递归的形式&#xff1a; 直接递归&#xff1a;方法自己调用自己。 间接递…

【监控】Spring Boot+Prometheus+Grafana实现可视化监控

目录 1.概述 2.spring actuator 3.Prometheus 3.1.介绍 3.2.使用 1.client端的配置 2.server端的配置 4.grafana 5.留个尾巴 1.概述 本文是博主JAVA监控技术系列的第四篇&#xff0c;前面已经聊过了JMX、Spring actuator等技术&#xff0c;本文我们就将依托于Spring …

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并

利用docker一键部署LLaMa到自己的Linux服务器,有无GPU都行、可以指定GPU数量、支持界面对话和API调用,离线本地化部署包含模型权重合并。两种方式实现支持界面对话和API调用,一是通过搭建text-generation-webui。二是通过llamma.cpp转换模型为转换为 GGUF 格式,使用 quanti…

Leetcode日记 889. 根据前序和后序遍历构造二叉树

Leetcode日记 889. 根据前序和后序遍历构造二叉树 给定两个整数数组&#xff0c;preorder 和 postorder &#xff0c;其中 preorder 是一个具有 无重复 值的二叉树的前序遍历&#xff0c;postorder 是同一棵树的后序遍历&#xff0c;重构并返回二叉树。 如果存在多个答案&#…

petalinux_zynq7 驱动DAC以及ADC模块之二:petalinux

petalinux_zynq7 C语言驱动DAC以及ADC模块之一&#xff1a;建立IPhttps://blog.csdn.net/qq_27158179/article/details/136234296在上一篇&#xff0c;建立了ADC和DAC两个IP。这里继续。本文在 petalinux默认配置的基础上&#xff0c;添加了python和qt。再编译出sdk可以给x86主…

汽车智能座舱中 显示屏市场战略趋势分析 中篇

今天主要讲讲主流车厂显示屏的趋势。 主流车厂的中控&液晶仪表屏的尺寸及趋势汇总 奔驰 奔驰A级 10.2510.25 奔驰C级 12.310.25 奔驰GLA 10.2510.25 奔驰E级 12.312.3 奔驰S级 12.312.8 1、奔驰的仪表几乎都为液晶仪表&#xff0c;几乎所有车型都有HUD的选配&#xff…

大功率应用中的厚膜电阻散热器的设计?

在许多大功率应用中&#xff0c;例如电机和电源&#xff0c;电源电阻器位于主电源线中。它们的目的是防止损坏或提供一定程度的控制。 在这些应用中&#xff0c;电阻器承受恒定的、相对较高的电流。当电流流过电阻器时&#xff0c;它会产生热量。这种热能必须消散到环境中&…

1、WEB攻防-通用漏洞SQL注入MYSQL跨库ACCESS偏移

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正&#xff01; 前言&#xff1a; 为了网站和数据库的安全性&#xff0c;MYSQL 内置有 ROOT 最高用户&#xff0c;划分等级&#xff0c;每个用户对应管理一个数据库&#xff0c;这样保证无不关联&#xff0c;从而不会影响到其他…

Autosar-WdgM配置详解-3

1.11生成代码解析 1.11.1MasterSWC代码解析 在MasterSWC的RE_TestRun这个runnable里会调用两个检测点函数,我们可以在两个检测点函数之间,加入我们所需要监控的代码。 Rte_Call_RPort_StartCheckPoint_CheckpointReached(); Rte_Call_RPort_EndCheckPoint_CheckpointReac…

C#串口 Modbus通讯工具类

一、安装Modbus包 二、创建modbushelper类 1、打开串口 public bool IfCOMOpend; //用于实例内的COM口的状态 public SerialPort OpenedCOM;//用于手动输入的COM转成SERIAL PORT /// <summary> /// 打开串口 /// </summary> /// <param name="COMname&quo…

c++服务器开源项目Tinywebserver运行

c服务器开源项目Tinywebserver运行 一、Tinywebserver介绍二、环境搭建三、构建数据库四、编译Tinywebserver五、查看效果 Tinywebserver是github上一个十分优秀的开源项目&#xff0c;帮助初学者学习如何搭建一个服务器。 本文讲述如何在使用mysql跟该项目进行连接并将项目运行…

python 层次分析(AHP)

文章目录 一、算法原理二、案例分析2.1 构建指标层判断矩阵2.2 求各指标权重2.2.1 算术平均法&#xff08;和积法&#xff09;2.2.2 几何平均法&#xff08;方根法&#xff09; 2.3 一致性检验2.3.1 求解最大特征根值2.3.2 求解CI、RI、CR值2.3.3 一致性判断 2.4 分别求解方案层…

利用Ubuntu22.04启动U盘对电脑磁盘进行格式化

概要&#xff1a; 本篇演示利用Ubuntu22.04启动U盘的Try Ubuntu模式对电脑磁盘进行格式化 一、说明 1、电脑 笔者的电脑品牌是acer(宏碁/宏基) 开机按F2进入BIOS 开机按F12进入Boot Manager 2、Ubuntu22.04启动U盘 制作方法参考笔者的文章&#xff1a; Ubuntu制作Ubun…

缓存篇—缓存雪崩

什么是缓存雪崩 通常我们为了保证缓存中的数据与数据库中的数据一致性&#xff0c;会给 Redis 里的数据设置过期时间&#xff0c;当缓存数据过期后&#xff0c;用户访问的数据如果不在缓存里&#xff0c;业务系统需要重新生成缓存&#xff0c;因此就会访问数据库&#xff0c;并…