# 小程序手动接入

该文档适用于 PC 小程序、低基础库运行小程序、硬件框架运行小程序、小程序插件

一般情况下,推荐使用一键接入,支持各种灰度、一键断连、预热等配置下发,更灵活安全。但在某些特殊场景(如 PC端、Web、需要兼容低版本时)下,可以使用如下的手动接入方案。

我们也配套上线了视频课程,你可以前往文档底部的视频课程学习这一部分。

重要:使用手动接入方案之前,需要做以下两个步骤:

  1. 微信公众平台 中将网关域名(a****-********.sh.wxcloudrun.com) 手动加入到 request 合法域名中。
  2. 如需要完全手动完成,不要自动接入干预,需登录 安全网关控制台,在对应小程序业务配置中-高级设置,配置要手动接入的域名列表(这里的域名是业务域名)

# 一、原生小程序

# 1. 在 app.json 中,添加使用 cloud: true 能力覆盖低版本基础库,具体操作如下:

// app.json,如果是 uniapp 在 manifest.json 中 mp-weixin 字段,如果是 taro 在 app.config.js
{
  "cloud": true,
  "cloudVersion": "alpha"
}

# 2. 真机验证引入效果

配置生效后,强烈建议在真机预览,测试是否异常,是否会影响原有正常业务。

# 3. 补充手动接入代码逻辑

cloud: true 能力不支持「一键接入」等能力,需要手动完成对应能力的实现。

可以通过在 app.js 中的 onLaunch 添加如下代码实现劫持 wx.request 实现类似一键接入的效果

// 参考实现,通过劫持 wx.request 完成类似一键接入的效果
App({
    onLaunch() {
        const gateway = wx.cloud.services.Gateway({
            // 接入域名:即在网关接入层生成的域名,请复制“域名配置”中网关的接入域名。
            domain: 'a****-********.sh.wxcloudrun.com',
        })
        // 赋值到 cloud 对象上,方便后续调用
        wx.cloud.gateway = gateway
        const __origin_req = wx.request;
        const gatewayDomainList = [
            "https://domain"
        ] // url 前缀匹配命中 gatewayDomainList 中的访问请求,将使用网关进行访问
        function checkGateway(url) {
            for (const element of gatewayDomainList) {
                if (url.startsWith(element)) {
                    return true
                }
            }
            return false
        }
        // 重写 wx.request
        function request(option) {
            if (checkGateway(option.url)) {
                if (!option.header) option.header = {}
                option.header['X-WX-HTTP-MODE'] = "REROUTE"
                option.header['X-WX-CONF-VERSION'] = "0"
                return gateway.call({
                    path: option.url,
                    ...option, // success 回调在这里注册
                    fail: (err) => {
                      // 如果需要回退到 wx.request,使用第一行进行重试
                      // 如果不需要回退到 wx.request,使用第二行进入 fail 回调
                      return __origin_req(option)
                      // return option.fail(err)
                    }
                })
            }
            return __origin_req(option)
        }
        Object.defineProperty(wx, 'request', {
          value: request,
          enumerable: true,
          configurable: true,
        })
    }
})

# 二、Taro 等第三方框架

部分第三方框架不支持重写 wx.request,可以使用官方拦截器的方案接入,具体操作如下:

# 1. 创建 gateway.js

# 1.1 Taro 示例:
import Taro from '@tarojs/taro'

// 网关域名白名单,以下地址开头的 URL 将会通过网关访问
const GATEWAY_INTERCEPT_URLS = [
  'https://example.com'
]

if (Taro.getEnv() === Taro.ENV_TYPE.WEAPP) {
  const gateway = wx.cloud.services.Gateway({
    // 接入域名:即在网关接入层生成的域名,请复制“域名配置”中网关的接入域名。
    domain: '***your-domain***.sh.wxcloudrun.com',
  })

  const gatewayInterceptor = (chain) => {
    const params = chain.requestParams
    if (GATEWAY_INTERCEPT_URLS.some(url => params.url.startsWith(url))) {
      return gateway.call({
        ...params,
        header: {
          ...params.header,
          'X-WX-HTTP-MODE': 'REROUTE',
          'X-WX-CONF-VERSION': '0',
        },
        path: params.url,
      })
    } else {
      return chain.proceed(params)
    }
  }
  Taro.addInterceptor(gatewayInterceptor)
}
# 1.2 Uniapp 示例:
// #ifdef MP-WEIXIN

// 网关域名白名单,以下地址开头的 URL 将会通过网关访问
const GATEWAY_INTERCEPT_URLS = [
  'https://example.com'
]
const gateway = wx.cloud.services.Gateway({
  // 接入域名:即在网关接入层生成的域名,请复制“域名配置”中网关的接入域名。
  domain: '****.sh.wxcloudrun.com',
})


uni.addInterceptor('request', {
  invoke(params) {
    if (GATEWAY_INTERCEPT_URLS.some(url => params.url.startsWith(url))) {
      return gateway.call({
        ...params,
        header: {
          ...params.header,
          'X-WX-HTTP-MODE': 'REROUTE',
          'X-WX-CONF-VERSION': '0',
        },
        path: params.url,
      })
    }
  },
})

// #endif

# 2. 在 app.js 引入上述 JS

import './gateway.js'

# 3. 测试请求是否正常

# 三、API 接入

如果需要使用更细粒度的接入方案,可以使用 API 接入的形式:

interface GatewayCallParam {
  path: string
  header: Record<string, string>
  data?: string | ArrayBuffer | any
  method?: string
  success?: (res: GatewayCallResult) => void
  fail?: (err: Error) => void
}
interface GatewayCallResult {
  data: any
  statusCode: number
  header: Record<string, any>
  callID: string
}
interface GatewayInstance {
    call: (param: GatewayCallParam) => Promise<GatewayCallResult>
}
declare interface WxCloud {
    services: {
        Gateway: (opts: { domain: string }) => GatewayInstance
    }
    gateway: GatewayInstance
}
declare interface Wx {
    cloud: WxCloud
}

使用示例如下

const gateway = wx.cloud.services.Gateway({
      // 接入域名,可以在网关控制台中获取
      domain: 'a******.sh.wxcloudrun.com',
})
// 赋值到 cloud 对象上,方便后续调用
wx.cloud.gateway = gateway

const result = wx.cloud.gateway.call({
      // 填写完整域名(包括协议头和 host 部分,如 https://api.example.com/path?query=xxx)
      // 如果 URL 中包含中文,需要手动 encode
      path: 'https://httpbin.org/get?query=xxx',
      // 请求方法
      method: 'GET',
      // 请求 header
      header: {
           //! 重要:需要携带这个 Header,以启用多域名支持能力
          'X-WX-HTTP-MODE': 'REROUTE',
           //! 手工接入需要携带的特殊字段,跳过版本号检查
          'X-WX-CONF-VERSION': '0',
      }
      // 其余参数与 wx.request 相同
}).then(result => {
      console.log(result)
})

# 四、FAQ

# 1. 手动接入有什么局限性?

  • 手动接入请务必自行将网关域名添加到 MP 合法域名中,否则网关将触发链路切换,导致请求变慢或出现异常
  • 手动接入时无法使用如下网关能力:原生加解密优化,网关性能根据业务场景,会有一定影响。
  • 如果网关到期或者超过流量限制,会进入 fail 回调,需要开发者手动处理

# 2. 手动接入如何灰度流量?

手动接入时,可以使用 API 接入的形式,自行决定使用 gateway.call 还是 wx.request 进行请求

# 3. 手动接入支持到什么版本?

  • 微信:2.14.1 基础库版本及以上
  • 企业微信:2.20.3 基础库版本及以上
  • Web SDK:2.0.3 SDK 版本及以上

具体情况以真机为准,在启用 cloud:true 的小程序中,会提示 using cloud: true 的信息