微信小程序学习日记 L04 网络请求

在小程序中发送网络请求,需要使用微信提供的API,提供了5种:

  • 普通 HTTPS 请求(wx.request
  • 上传文件(wx.uploadFile
  • 下载文件(wx.downloadFile)
  • WebSocket 通信(wx.connectSocket
  • UDP 通信(wx.createUDPSocket

一般项目中使用频率最高的是 wx.requestwx.uploadFile

需要注意的是,小程序只可以跟指定的域名进行网络通信,需要事先设置通讯域名(服务器域名请在 「小程序后台-开发-开发设置-服务器域名」 中进行配置)。

可以查看 配置流程 了解一下具体注意项。


#1 HTTPS 请求

wx.request(options) 可以传入一个 options 对象,具体可以配置哪些参数可以查看 发起请求 - 参数 ,我就不一一例出来了。

简单的上一个登陆请求示例:

wx.request({
  url: 'https://example.weixin.qq.com/login', // 接口地址
  data: { // 请求参数
    uid: 'admin',
    pwd: '123456'
  },
  header: { // 请求头
    'content-type': 'application/json' // 默认json,为了举例我还是写上来了
  },
  method:'POST', // 请求类型
  success (res) {
    // 接口调用成功的回调函数
  },
  fail (err) {
    // 接口调用失败的回调函数
  }
})

需要注意的是:

  1. 不支持以 Promise 风格 调用。
    Promise 风格 是基础库版本 2.10.2 起开始支持的新调用方式,旧版本只能使用 callback 的形式来处理
  2. 最终发送给服务器的数据是 String 类型,如果传入的 data 不是 String 类型,会被转换成 String ,可以查看 data 参数说明

不过一般我会自己把请求函数 Promisify,如下

// request.js
export function request ({ url, method, data, contentType = {} }) {
  const { requestUrl } = getApp().globalData // 在 app.js 设置的全局变量
  const apiUrl = requestUrl + url // 拼接完整请求地址
  const token = wx.getStorageSync("token")
  const header = Object.assign({ "content-type": "application/json", "X-Access-Token": token }, contentType)
  console.info("请求接口: ", apiUrl);
  console.info("请求头部: ", header)
  console.info("请求参数: ", data)
  return new Promise((resolve, reject) => {
    wx.request({
      url: apiUrl,
      data: data,
      method: method,
      header: header,
      success (res) {
        console.info(`[${apiUrl}]请求返回值:`);
        console.table(res.data)
        const { success, result, message } = res.data
        if(success) {
          resolve(res.data)
        } else {
          reject(res.data)
          console.warn("ERROR_URL:", url)
          return onErr(res.data) // 异常处理
        }
      },
      fail (err) {
        reject(err)
        Toast({ title: "服务器异常,请重试!" }) // 封装的wx.showToast()
        console.warn("----------请求异常-----------")
        console.warn(err)
      }
    })
  })
}

然后再封装一下不同的请求方法,在使用的时候按需引入就好了

// manage.js
import { request } from './request'
export const FORM_DATA = {"content-type": "application/x-www-form-urlencoded;charset=UTF-8"}
// post
export function postAction (url, parameter, contentType = {}) {
  return request({
    url: url,
    method: 'POST',
    data: parameter,
    contentType:contentType,
  })
}
// http method= {POST | PUT}
export function httpAction (url, parameter = {}, method, contentType = {}) {
  return request({
    url: url,
    method: method,
    data: parameter,
    contentType:contentType,
  })
}
// put
export function putAction (url, parameter = {}, contentType = FORM_DATA) {
  return request({
    url: url,
    method: 'PUT',
    data: parameter,
    contentType:contentType,
  })
}
// get
export function getAction (url, parameter = {}, contentType = {}) {
  return request({
    url: url,
    method: 'GET',
    data: parameter,
    contentType:contentType,
  })
}
// delete
export function deleteAction (url, parameter = {}, contentType = {}) {
  return request({
    url: url,
    method: 'DELETE',
    data: parameter,
    contentType:contentType,
  })
}

是不是有一股子 Ant Design Vue Pro 的味道 😂😂😂

#2 上传文件

wx.uploadFile(options),可以传入一个 options 对象,参数配置文档

注意:客户端发起一个 HTTPS POST 请求,其中 content-typemultipart/form-data

示例代码:

wx.chooseImage({
  success (res) {
    const tempFilePaths = res.tempFilePaths // 获取的文件临时路径
    wx.uploadFile({
      url: 'https://example.weixin.qq.com/upload', // 请求的网络接口
      filePath: tempFilePaths[0], // 文件路径
      name: 'file', // 文件key,服务端可以通过这个 key 获取文件二进制内容 
      formData: { // 额外的 formData 可以不传
        'user': 'test'
      },
      success (result){
        // 接口调用成功的回调函数
      },
      fail (error){
        // 接口调用失败的回调函数
      }
    })
  }
})

同样也会封装成 Promise

// request.js
export function uploadFile ({ url, data }) {
  const { requestUrl } = getApp().globalData // 在 app.js 设置的全局变量
  const apiUrl = requestUrl + url
  const token = wx.getStorageSync("token")
  const header = { "X-Access-Token": token }
  console.info("请求接口: ", apiUrl);
  console.info("请求头部: ", header)
  console.info("文件地址: ", data)
  return new Promise((resolve, reject) => {
    wx.uploadFile({
      url: apiUrl,
      filePath: data.filePath,
      name: 'file',
      header: header,
      success: (res) => {
        console.info(`[${apiUrl}]请求返回值:`);
        console.table(res.data)
        const { data, statusCode } = res
        if (statusCode !== 200){
          Toast({ title: "上传失败" })
          reject(res.data)
          return
        }
        // 这里需要注意是否返回的是JSON格式的 data
        const d = JSON.parse(data)
        const { success, result, message } = data
        if (success) {
          resolve(d)
        } else {
          reject(res.data)
          console.warn("ERROR_URL:", url)
          return onErr(d) // 异常处理
        }
      },
      fail (err) {
        reject(err)
        Toast({ title: "服务器异常,请重试!" })
        console.warn("-----------上传失败-----------");
        console.warn(err);
      }
    })
  })
}

#3 下载文件

wx.downloadFile(options),同样也可以传入一个 options 对象,配置文档 DownloadTask | 微信开放文档

  • 发起一个 HTTPS GET 请求
  • 返回文件的本地临时路径 (本地路径)
  • 单次下载允许的最大文件为 200MB

注意:请在服务端响应的 header 中指定合理的 Content-Type 字段,以保证客户端正确处理文件类型。

示例代码

wx.downloadFile({
  url: 'https://example.com/audio/123', // 仅为示例,并非真实的资源
  success (res) {
    // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
    if (res.statusCode === 200) {
      wx.playVoice({
        filePath: res.tempFilePath
      })
    }
  }
})

暂时还没有使用的场景,就暂时不描述了,WebSocket 也是还没有在小程序业务上使用过,就不细说了,简单的用文档中的示例

#4 WebSocket 通信

首先需要使用 wx.connectSocket(options) 创建一个 WebSocket 连接。具体文档 SocketTask | 微信开放文档
然后就和正常使用 WebSocket 一样了:

方法

  • wx.sendSocketMessage(Object object) 通过 WebSocket 连接发送数据。
  • wx.closeSocket(Object object) 关闭 WebSocket 连接

事件

  • 全局事件
    • wx.onSocketOpen(callback) 监听 WebSocket 连接打开事件
    • wx.onSocketMessage(callback) 监听 WebSocket 接受到服务器的消息事件
    • wx.onSocketError(callback) 监听 WebSocket 错误事件
    • wx.onSocketClose(callback) 监听 WebSocket 连接关闭事件
  • 当前Socket事件
    • 通过 wx.connectSocket() 接口创建返回赋值给变量 SocketTask
    • SocketTask.onSocketOpen(callback) 监听 WebSocket 连接打开事件
    • SocketTask.onSocketMessage(callback) 监听 WebSocket 接受到服务器的消息事件
    • SocketTask.onSocketError(callback) 监听 WebSocket 错误事件
    • SocketTask.onSocketClose(callback) 监听 WebSocket 连接关闭事件

#5 UDP 通信

使用 wx.createUDPSocket() 创建一个 UDP Socket 实例,之后就可以和 WebSocket 通信类似的方式使用 UDPSocket API来通信了,具体文档 UDPSocket | 微信开放文档

方法

  • UDPSocket.bind(number port) 绑定一个可用端口号
  • UDPSocket.send() 向指定的 IP 和 port 发送消息
  • UDPSocket.connect(Object object) 预先连接到指定的 IP 和 port,需要配合 write 方法一起使用
  • UDPSocket.write() 用法与 send 方法相同,如果没有预先调用 connect 则与 send 无差异
  • UDPSocket.close() 关闭 UDP Socket 实例,相当于销毁

事件

  • UDPSocket.onClose(callback) 监听关闭事件
  • UDPSocket.offClose(callback) 取消监听关闭事件
  • UDPSocket.onError(callback) 监听错误事件
  • UDPSocket.offError(callback) 取消监听错误事件
  • UDPSocket.onListening(callback) 监听开始监听数据包消息的事件
  • UDPSocket.offListening(callback) 取消监听开始监听数据包消息的事件
  • UDPSocket.onMessage(callback) 监听收到消息的事件
  • UDPSocket.offMessage(callback) 取消监听收到消息的事件

错误码之类的直接看 文档 吧。
这个API应该是和我无缘了,物联网和直播之类的场景我应该是很难遇到的。

其它

📌 配置网络请求超时时间

如果需要配置超时时间则需要去 app.json 中配置 networkTimeout
默认 60000 (单位:毫秒),最大超时时间也是 60000
可以为4个网络请求单独配置超时时间,具体查看 👉 配置文档

// app.json
{
  // 其他配置项....
  "networkTimeout": {
    "request": 10000, // wx.request 的超时时间 
    "uploadFile": 10000 // wx.uploadFile 的超时时间
  }
}

资源

网络 | 微信开放文档
RequestTask | 微信开放文档
API Promise化 | 微信开放文档

WebSocket - Web API 接口参考 | MDN