微信小程序 --- 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.pswp.cn/news/696990.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696990.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696990.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【精選】Java面向對象進階——內部類

🍬 博主介紹👨?🎓 博主介紹:大家好,我是 hacker-routing ,很高興認識大家~ ?主攻領域:【滲透領域】【應急響應】 【Java】 【VulnHub靶場復現】【面試分析】 🎉點贊?評論?收藏 …

【操作系統】磁盤文件管理系統

實驗六 磁盤文件管理的模擬實現 實驗目的 文件系統是操作系統中用來存儲和管理信息的機構,具有按名存取的功能,不僅能方便用戶對信息的使用,也有效提高了信息的安全性。本實驗模擬文件系統的目錄結構,并在此基礎上實現文件的各種…

FISCO BCOS(十七)利用腳本進行區塊鏈系統監控

要利用腳本進行區塊鏈系統監控,你可以使用各種編程語言編寫腳本,如Python、Shell等 利用腳本進行區塊鏈系統監控可以提高系統的穩定性、可靠性,并幫助及時發現和解決潛在問題,從而確保區塊鏈網絡的正常運行。本文可以利用腳本來解…

Java實戰:分布式Session解決方案

本文將詳細介紹Java分布式Session的解決方案。我們將探討分布式Session的基本概念,以及常見的分布式Session管理技術,如Cookie、Token、Redis等。此外,我們將通過具體的示例來展示如何在Java應用程序中實現分布式Session。本文適合希望了解和…

Swift基礎知識:21.Swift繼承

在 Swift 中,類可以通過繼承從其他類獲得屬性和方法。被繼承的類稱為父類(或超類),繼承的類稱為子類。子類可以繼承父類的特性,并且可以添加自己的新特性。繼承允許類層次結構中的代碼重用和多態性。 定義一個基類&am…

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生態…

(delphi11最新學習資料) Object Pascal 學習筆記---第5章第3節(自定義托管記錄)

5.3.5 運算符和自定義托管記錄 ? 在 Delphi 語言中&#xff0c;有一組特殊的運算符可用于記錄&#xff0c;以定義自定義托管記錄。在此之前&#xff0c;請允許我回顧一下記錄內存初始化的規則&#xff0c;以及普通記錄和托管記錄之間的區別。 ? Delphi 中的記錄可以包含任何…

大語言模型LangChain本地知識庫:向量數據庫與文件處理技術的深度整合

文章目錄 大語言模型LangChain本地知識庫&#xff1a;向量數據庫與文件處理技術的深度整合引言向量數據庫在LangChain知識庫中的應用文件處理技術在知識庫中的角色向量數據庫與文件處理技術的整合實踐挑戰與展望結論 大語言模型LangChain本地知識庫&#xff1a;向量數據庫與文件…

【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;重構并返回二叉樹。 如果存在多個答案&#…

【Flink集群RPC通訊機制(三)】AkkaRpcActor設計與實現:接收RPC消息以及處理邏輯

文章目錄 1. 創建Receiver2. 進行消息處理 RPC請求發送后接收方的處理邏輯 在RpcEndpoint中創建的RemoteRpcInvocation消息&#xff0c;最終會通過Akka系統傳遞到被調用方。例如TaskExecutor向ResourceManager發送SlotReport請求的時候&#xff0c;會在TaskExecutor中將Resourc…

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…