# 小程序手动接入安全网关

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

重要:需要在 微信公众平台 中将网关域名(a****-********.sh.wxcloudrun.com) 手动加入到 request 合法域名中。

# 低版本覆盖(无框架)

  1. 在 app.json 中,添加使用 cloud: true 能力覆盖低版本基础库,具体操作如下:
// app.json,如果是 uniapp 在 manifest.json 中 mp-weixin 字段,如果是 taro 在 app.config.js
{
  "cloud": true,
  "cloudVersion": "alpha"
}
  1. 配置生效后,强烈建议在真机进行测试是否异常

  2. cloud: true 能力不支持「一键接入」「自动回退」「中文 URL 参数」等能力,需要手动完成对应能力的实现。可以通过在 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 前缀匹配命中 gw_domain_list 中的访问请求,将使用cloudsdk进行访问
        function checkGateway(url) {
            for (const element of gatewayDomainList) {
                if (url.startsWith(element)) {
                    return true
                }
            }
            return false
        }
        // 重写 wx.request
        wx.request = function (option) {
            if (checkGateway(option.url)) {
                option.header['X-WX-HTTP-MODE'] = "REROUTE"
                option.header['X-WX-CONF-VERSION'] = "0"
                return gateway.call({
                    // 填写完整域名(包括协议头和 host 部分,如 https://api.example.com/path?query=xxx)
                    // 如果 URL 中包含中文,需要手动 encode
                    path: option.url,
                    ...option
                }).then(option.success).catch(option.fail)
            }
            return __origin_req(option)
        }
    }
})

# Taro 等第三方框架

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

  1. 创建 gateway.js,内容如下

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)
}

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
  1. 在 app.js 中,引入上述 JS
import './gateway.js'
  1. 测试请求是否正常即可

# 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

Q:手动接入有什么局限性?

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

Q:手动接入如何灰度流量?

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

Q:手动接入支持到什么版本?

  • 微信:2.14.1 基础库版本及以上
  • 企业微信:2.20.3 基础库版本及以上
  • Web SDK:2.0.3 SDK 版本及以上 具体情况以真机为准,在启用 cloud:true 的小程序中,会提示 using cloud: true 的信息