当前位置: 首页 > news >正文

微信小程序 --- 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)}
})

相关文章:

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

网络请求封装 网络请求模块难度较大,如果学习起来感觉吃力,可以直接学习 [请求封装-使用 npm 包发送请求] 以后的模块 01. 为什么要封装 wx.request 小程序大多数 API 都是异步 API,如 wx.request(),wx.login() 等。这类 API 接口…...

通义千问Qwen-7B-Chat Windows本地部署教程-详细认真版

通义千问本地部署教程🚀 本专栏的第四弹,在实现了联网调用通义千问模型进行多轮对话,流式输出,以及结合LangChain实现自建知识库之后,开始准备考虑实现对大模型进行本地部署,网上找不到看着比较舒服的教程&…...

探索C语言位段的秘密

位段 1. 什么是位段2. 位段的内存分配3. 位段的跨平台问题4. 位段的应用4. 使用位段的注意事项 1. 什么是位段 我们使用结构体实现位段,位段的声明和结构体是类似的,有两个不同: 位段的成员必须是int,unsigned int,或…...

数据库-数据库设计-社交关系

佛 每有一个新方案,就要考虑有什么影响增删改查可扩展性 MySQL 根据ER图设计表 create table follow(id bigint unsigned not null auto_increment comment 主键,gmt_create datetime null default current_timestamp,gmt_modified null default current_timest…...

YOLO算法改进Backbone系列之:EfficientViT

EfficientViT: Memory Effificient Vision Transformer with Cascaded Group Attention 摘要:视觉transformer由于其高模型能力而取得了巨大的成功。然而,它们卓越的性能伴随着沉重的计算成本,这使得它们不适合实时应用。在这篇论文中&#x…...

JANGOW: 1.0.1

kali:192.168.223.128 主机发现 nmap -sP 192.168.223.0/24 端口扫描 nmap -p- 192.168.223.154 开启了21 80端口 web看一下,有个busque.php参数是buscar,但是不知道输入什么,尝试文件包含失败 扫描目录 dirsearch -u http://192.168.223.154 dirse…...

Elasticsearch 创建index库 timeout

问题概述 使用 python 客户端 代码进行创建,【之前成功创建,但是现在出现报错,报错代码es_connection.client.indices.create】def create_vector_index(dataset_index_name,vector_query_field,query_field):es_connection = get_collention(dataset_index_name,vector_que…...

2024最新可用免费天气预报API接口

天气API接口数据, 数据字段最全,免费,稳定的实况天气预报接口 5分钟左右更新一次,支持全国3000多个市区县, 包含基本天气信息、24小时逐小时天气、气象预警列表、湿度、能见度、气压、降雨量、紫外线、风力风向风速、日出日落、空气质量、pm2…...

【AIGC】开源声音克隆GPT-SoVITS

GPT-SoVITS 是由 RVC 创始人 RVC-Boss 与 AI 声音转换技术专家 Rcell 共同开发的一款跨语言 TTS 克隆项目,被誉为“最强大中文声音克隆项目” 相比以往的声音克隆项目,GPT-SoVITS 对硬件配置的要求相对较低,一般只需 6GB 显存以上的 GPU 即可…...

YOLOv9图像标注和格式转换

一、软件安装 labelimg安装(anaconda) 方法一、 pip install labelImg 方法二、 pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install pyqt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install lxml -i ht…...

车载系统相关

车载SBL和EC系统介绍 一、概述 车载SBL(Signal Broadcasting Layer)和EC(Electronic Control)系统是现代汽车中不可或缺的组成部分。它们共同协作,确保车辆的稳定、安全和高效运行 二、SBL系统介绍 SBL系统&#x…...

AWS对文本进行语言识别

AWS提供了名为Amazon Comprehend 的服务,它支持对文本进行语言识别。Amazon Comprehend 是一项自然语言处理(NLP)服务,它可以用于分析文本并提取有关文本内容的信息。 我们可以通过使用 Amazon Comprehend API 轻松地集成这些功能…...

HTTP 与HTTPS笔记

HTTP 80 HTTP是一个在计算机世界里专门在【两点】之间【传输】文字、图片、音频、视频等【超文本】数据的约定和规范。 HTTP状态码 1xx 提示信息,表示目前是协议处理的中间状态,还需要后续的操作;2xx 200 204 026 成功3xx 重定向&#xff…...

【k8s配置与存储--配置管理】

1、ConfigMap的配置 1.1 ConfigMap介绍 ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pod 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。 ConfigMap 将你的环境配置信息和容器镜像解耦,便于应用配…...

如何在C++中嵌入SQL语句?解释一下什么是ODBC、JDBC以及它们在C++数据库编程中的作用。

如何在C中嵌入SQL语句? 在C中嵌入SQL语句通常涉及使用数据库连接库或ORM(对象关系映射)框架,这些工具提供了与特定数据库管理系统(DBMS)交互的接口。以下是几种在C中嵌入SQL语句的常见方法: 使…...

【Simulink系列】——动态系统仿真 之 混合系统

声明:本系列博客参考有关专业书籍,截图均为自己实操,仅供交流学习! 一、混合系统概述 由不同类型系统共同构成的系统称为混合系统!仿真时必须考虑连续信号和离散信号的采样匹配问题,一般使用变步长连续求…...

PHP中的飞碟运算符、取反运算符、对比非ASCII字符串、对比浮点数操作

对比浮点数 在电脑里存储的浮点数可能会和输入的值有些许差异,比如输入的是10.0,但存储的是10.00001. 在比较两个浮点数是否相等时可以计算下两个数的差值,然后查看下两数之差是否小于可以接受的阈值,如果要求精度在小数点后5位的…...

unity-unity2d基础操作笔记(二)0.5.0

unity2d基础操作笔记 五十一、canvas中的必须熟悉的属性五十二、如何调整canvas与游戏人物大小近似大小五十三、canvas中的canvas scaler介绍【概念】五十四、ui scale mode介绍【概念】五十五、为什么创建image后,canvas的范围要要远远大于游戏世界?五十六、图片常用操作【技…...

Feign远程调用(学习笔记)

先来看我们以前利用RestTemplate发起远程调用的代码: 存在下面的问题: ●代码可读性差,编程体验不统一 ●参数复杂URL难以维护 Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign 其作用…...

pytorch建模的三种方式

# 可以使用以下3种方式构建模型: # # 1,继承nn.Module基类构建自定义模型。 # # 2,使用nn.Sequential按层顺序构建模型。 # # 3,继承nn.Module基类构建模型并辅助应用模型容器进行封装(nn.Sequential,nn.ModuleList,nn.ModuleDict…...

GO-ICP的使用(一)

一、代码下载以、修改以及使用 下载: 链接:yangjiaolong/Go-ICP: Implementation of the Go-ICP algorithm for globally optimal 3D pointset registration (github.com) 解压之后 : 首先visual studio项目,配置好PCL环境&…...

FPS游戏漫谈System.GC.Collect()强制进行垃圾回收

在Unity中,System.GC.Collect()用于强制进行垃圾回收,但是它是一个相当耗时的操作,可能会导致游戏的帧率下降,甚至出现卡顿。因此,你应该尽量避免在游戏的主循环中频繁调用它。以下是一些关于在Unity中使用System.GC.C…...

第3集《灵峰宗论导读》

《灵峰宗论》导读。诸位法师,诸位同学,阿弥陀佛!(阿弥陀佛!) 请大家打开讲义第5面,悟道。 这一科我们是说明论主略史,在这一科当中,我们根据弘一大师所编的《蕅益大师年…...

java面试设计模式篇

面试专题-设计模式 前言 在平时的开发中,涉及到设计模式的有两块内容,第一个是我们平时使用的框架(比如spring、mybatis等),第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…...

桥接模式:解耦抽象与实现,实现灵活多变的扩展结构

文章目录 一、引言二、应用场景与技术背景三、模式定义与实现四、实例详解五、优缺点分析总结: 一、引言 ​ 桥接模式是一种结构型设计模式,它将抽象部分与它的实现部分分离,使它们可以独立变化。这种模式通过创建一个抽象层和实现层的结构&…...

HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)

D - Square Pair 题目大意 给一长为的数组,问有多少对,两者相乘为非负整数完全平方数 解题思路 一个数除以其能整除的最大的完全平方数,看前面有多少个与其余数相同的数,两者乘积满足条件(已经是完全平方数的部分无…...

Heap sorting

堆排序比较特殊&#xff0c;采用数组表示堆。 先将数组表示成大根堆或者小根堆。然后从堆中依次取根&#xff0c;最后形成有序序列。 #include<bits/stdc.h> using namespace std;const int N 1e5 10; int a[N];void bigheap(int* a, int start, int len) {if(start …...

开源模型应用落地-qwen2模型小试-入门篇(六)

一、前言 经过前五篇“qwen模型小试”文章的学习,我们已经熟练掌握qwen大模型的使用。然而,就在前几天开源社区又发布了qwen1.5版本,它是qwen2模型的测试版本。在基于transformers的使用方式上有较大的调整,现在,我们赶紧跟上脚步,去体验一下新版本模型的推理质量。 二、…...

c#程序,oracle使用Devart驱动解决第第三方库是us7ascii,数据乱码的问题

最近做项目&#xff0c;要跟对方系统的库进行读写&#xff0c;结果发现对方采用的是oracle的us7ascii编码&#xff0c;我们系统默认采用的是ZHS16GBK&#xff0c;导致我们客户端读取和写入对方库的数据都是乱码&#xff0c;搜索网上&#xff0c;发现需要采用独立的oracle驱动去…...

代码随想录算法训练营第四一天 | 背包问题

目录 背包问题01背包二维dp数组01背包一维 dp 数组&#xff08;滚动数组&#xff09;分割等和子集 LeetCode 背包问题 01背包 有n件物品和一个最多能背重量为 w 的背包&#xff0c;第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#x…...

淮北网站建设/线上渠道推广有哪些方式

jQuery.post(url, [data], [callback], [type]) 通过远程 HTTP POST 请求载入信息。这是一个简单的 POST 请求功能以取代复杂 $.ajax 。请求成功时可调用回调函数。如果需要在出错时执行函数&#xff0c;请使用 $.ajax。参数 :urlString发送请求地址。data (可选)Map待发送 Key…...

wordpress主题转换/目前网络推广平台

1. 剑指 Offer 22. 链表中倒数第k个节点 输入一个链表&#xff0c;输出该链表中倒数第k个节点。为了符合大多数人的习惯&#xff0c;本题从1开始计数&#xff0c;即链表的尾节点是倒数第1个节点。例如&#xff0c;一个链表有6个节点&#xff0c;从头节点开始&#xff0c;它们的…...

西安php网站建设专家/sem是什么意思职业

Pandas库 Pandas库是一个专门用于数据分析的开源Python库&#xff0c;有Series&#xff08;序列&#xff09;和DataFrame&#xff08;数据框&#xff09;这两种数据结构。 1 Pandas简介 数据分析工作需要一个专门的库&#xff0c;它能够以最简单的方式提供数据处理、数据抽取…...

炫酷网站界面设计/百度推广培训

有任何的书写错误、排版错误、概念错误等&#xff0c;希望大家包含指正。 在阅读本篇之前建议先学习&#xff1a; RNN 讲解 LSTM 讲解 3. GRU 3.1. 网络结构 GRU 是循环神经网络的一种&#xff0c;和 LSTM 一样&#xff0c;是为了解决长期依赖问题。GRU 单元结构如下。 图 1…...

目前做美术的网站以及app/网络营销这个专业怎么样

&#xff08;下面内容均是来源于网友经验&#xff0c;我只是大自然的搬运工&#xff0c;多谢广大网友&#xff09; 原因应该是 &#xff1a;上次关机时未正常关机&#xff1b; 表现症状&#xff1a;QQ初始化失败&#xff0c;很多网页打不开&#xff0c;一些应用打不开&#xff…...

网站上线后/网站首页的优化

Python的信息太爆炸了吧&#xff01;将纳入高考内容、小学生教材开始接触Python、Python列入全国计算机等级考试……全民学Python的话题铺天盖地&#xff0c;中国的Python学习者是全球第一&#xff0c;人才如此泛滥&#xff0c;甚至以后孩子都会&#xff0c;学习它还能体现自身…...