# 微信小程序-访问云托管服务

微信小程序中操作微信云托管服务,使用小程序基础库中 wx.cloud 方法对象,无需引入额外的SDK。

需要注意,微信小程序基础库版本应该在 2.23.0 及以上,请务必配套在「小程序管理后台」-「设置」-「功能设置」-「基础库最低版本设置」中,将值设定为2.23.0 及以上。

# 使用优势(对比wx.request)

  1. 不耗费任何公网流量,前后端通信走内网;
  2. 天然免疫DDoS攻击,仅授权小程序/公众号可访问后端,其他人即便拿到环境id和服务名也无法访问;
  3. 通过微信就近接入节点加速,无视后端服务地域影响,没有跨地域延迟,后端无需多地部署;
  4. 无需在小程序后台配置「服务器域名」;
  5. 后端可直接获取用户信息,无需调接口即可以获取opneid等。

因此,如果云托管服务只有微信小程序/公众号会调用,建议在服务设置中关闭公网访问

# 使用前提

最简单的情况,「小程序」对「直属微信云托管环境」的服务进行访问,也就是登录微信云托管控制台时选择小程序进入的环境。

以上情况我们约定为A小程序,如果你希望另外一个 B小程序/B公众号 也可以访问 A小程序 的云托管环境:

  1. A小程序B小程序/B公众号同主体:需要配置资源复用

  2. A小程序B小程序/B公众号不同主体:推荐使用「微信开放平台-第三方平台」方式。

  3. A小程序B小程序/B公众号不同主体:将B小程序/B公众号视为「其他客户端」,通过公网访问。参考文档其他客户端-访问云托管服务。此方式下,B小程序/B公众号无法使用云调用/微信令牌,且需要配置「服务器域名」(使用云托管服务的默认公网域名/自定义域名均可)。

如果你对以上正在支持的能力有任何建议和期待,欢迎在官方交流群联系我们。

# 基本使用

在小程序中使用如下的代码(取代原有wx.request用法):

// 确认已经在 onLaunch 中调用过 wx.cloud.init 初始化环境(任意环境均可,可以填空)
const res = await wx.cloud.callContainer({
  config: {
    env: '填入云环境ID', // 微信云托管的环境ID
  },
  path: '/xxx', // 填入业务自定义路径和参数,根目录,就是 / 
  method: 'POST', // 按照自己的业务开发,选择对应的方法
  header: {
    'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
    // 其他header参数
  }
  // dataType:'text', // 默认不填是以JSON形式解析返回结果,若不想让SDK自己解析,可以填text
  // 其余参数同 wx.request
});

console.log(res);

如上使用前,需要在小程序app.js中,执行wx.init,如下代码:

App({
  async onLaunch() {
    // 使用callContainer前一定要init一下,全局执行一次即可
    wx.cloud.init()
    // 下面的请求可以在页面任意一处使用
    const result = await wx.cloud.callContainer({
      config: {
        env: 'prod-01', // 微信云托管的环境ID
      },
      path: '/', // 填入业务自定义路径和参数,根目录,就是 / 
      method: 'GET', // 按照自己的业务开发,选择对应的方法
      header: {
        'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
      }
      // dataType:'text', // 默认不填是以JSON形式解析返回结果,若不想让SDK自己解析,可以填text
    })
    console.log(result)
  }
})

如果资源复用情况下,需要在 wx.cloud.init 中填写环境来源的账号appid,

例如,小程序A(appid:WXAAA)的环境 prod_001 授权给 小程序B(appid:WXBBB),则应是如下:

const c1 = new wx.cloud.Cloud({
  resourceAppid: 'WXAAA', // 环境所属的账号appid
  resourceEnv: 'prod_001', // 微信云托管的环境ID
})
await c1.init()
await c1.callContainer({
  config: {
    env: 'prod_001', // 微信云托管的环境ID
  },
  path: '/xxx', // 填入业务自定义路径和参数,根目录,就是 / 
  method: 'POST', // 按照自己的业务开发,选择对应的方法
  // dataType:'text', // 如果返回的不是json格式,需要添加此项
  header: {
    'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
    // 其他header参数
  }
  // 其余参数同 wx.request
})

如果你想深入了解 callContainer 的原理,建议阅读这篇文章

在这里我们提供了一个万能的封装方法,无论是自己的小程序还是资源复用形态,均可以正常使用。

在小程序app.js中建立一个call方法,并将appid、环境ID、服务名称填入适当的位置

App({
  async onLaunch() {
    // 这里演示如何在app.js中使用,没有用请删掉
    // const res = await this.call({
    //   path:'/',
    //   method: 'POST'
    // })
    // console.log('业务返回结果',res)
  },
  /**
   * 封装的微信云托管调用方法
   * @param {*} obj 业务请求信息,可按照需要扩展
   * @param {*} number 请求等待,默认不用传,用于初始化等待
   */
  async call(obj, number=0){
    const that = this
    if(that.cloud == null){
      that.cloud = new wx.cloud.Cloud({
        resourceAppid: 'WXAAA', // 微信云托管环境所属账号,服务商appid、公众号或小程序appid
        resourceEnv: 'prod-001', // 微信云托管的环境ID
      })
      await that.cloud.init() // init过程是异步的,需要等待init完成才可以发起调用
    }
    try{
      const result = await that.cloud.callContainer({
        path: obj.path, // 填入业务自定义路径和参数,根目录,就是 / 
        method: obj.method||'GET', // 按照自己的业务开发,选择对应的方法
        // dataType:'text', // 如果返回的不是json格式,需要添加此项
        header: {
          'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
          // 其他header参数
        }
        // 其余参数同 wx.request
      })
      console.log(`微信云托管调用结果${result.errMsg} | callid:${result.callID}`)
      return result.data // 业务数据在data中
    } catch(e){
      const error = e.toString()
       // 如果错误信息为未初始化,则等待300ms再次尝试,因为init过程是异步的
      if(error.indexOf("Cloud API isn't enabled")!=-1 && number<3){
        return new Promise((resolve)=>{
          setTimeout(function(){
            resolve(that.call(obj,number+1))
          },300)
        })
      } else {
        throw new Error(`微信云托管调用失败${error}`)
      }
    }
  }
})

在page页面js中,可以如下使用:

const app = getApp()
Page({
  async onLoad(){
    const res = await app.call({
      path:'/'
    })
    console.log('业务返回结果',res)
  }
})

# 请求参数

wx.cloud.callContainer 其他参数,直接参考 wx.request API,在这里列举常用参数:

属性 类型 默认值 必填 说明 最低版本
config.env string 微信云托管环境 ID
path string 后端服务接口地址
data string/object/ArrayBuffer 请求的参数
header Object 设置请求的 header,header 中不能设置 Referer。
content-type 默认为 application/json
timeout number 超时时间,单位为毫秒.最大值不能超过15秒,否则无效
method string GET HTTP 请求方法
dataType string json 返回的数据格式
responseType string text 响应的数据类型
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

如果希望 wx.cloud.container 返回 Promise,请勿传 success, fail 和 complete

# object.method 的合法值

说明 最低版本
OPTIONS HTTP 请求 OPTIONS
GET HTTP 请求 GET
HEAD HTTP 请求 HEAD
POST HTTP 请求 POST
PUT HTTP 请求 PUT
DELETE HTTP 请求 DELETE
TRACE HTTP 请求 TRACE
CONNECT HTTP 请求 CONNECT

# object.dataType 的合法值

说明 最低版本
json 返回的数据为 JSON,返回后会对返回的数据进行一次 JSON.parse
其他 不对返回的内容进行 JSON.parse

# object.responseType 的合法值

说明 最低版本
text 响应的数据为文本
arraybuffer 响应的数据为 ArrayBuffer

# 后端直接获取用户信息

小程序向云托管服务发起callcontainer调用时,你的服务请求header中会自动带有用户信息,包括openid、unionid、ip地址、可信来源等等,无需再通过小程序wx.login登录,然后调接口置换,大幅简化了流程。

注意,资源复用情况下,获取openid的字段和普通获取不一致。

# 使用限制

  1. 请求大小限制100K(请求中不建议包含图片,可通过对象存储处理);
  2. 返回包大小限制 1000k。