# wx.cloud.callContainer 技术原理和使用指南
无论是在微信小程序还是在公众号H5中,cloud.callContainer
是微信团队推荐的调用云托管服务的方式。
但云托管服务本身也提供公网访问链接,为什么不直接使用 wx.request
或者在网页中发起 XHR 请求呢?推荐引入 callContainer
这种方式有什么具体技术背景?
本篇给大家深度讲解 callContainer
调用
# 一、传统调用方式
我们先来看一下,wx.request
调用方式:
const result = await wx.request({
url: 'https://www.example.com/postapi', //仅为示例,并非真实的接口地址
method: 'GET' // 按照自己的业务开发,选择对应的方法
})
console.log(res);
wx.request
和WEB浏览器中 XHR
都是一类,提供标准的网络请求方式,只不过 wx.request
是为微信小程序定制的。
这类请求大致分两个部分,DNS
和 TCP连接
。
其中DNS是指将域名信息发送网络内DNS服务器,换取域名映射的服务器IP地址,为接下来连接做准备。
获取IP地址后,小程序就向此IP的服务器建立请求链接,按照请求方法发送数据包,然后等待服务器回包,完成整个请求。
在这里有两个变量,第一个是DNS,如果用户网络中的DNS服务器被劫持,那么小程序收到的IP地址是错误的,而后向错误的IP地址发送请求包,这种情况被称为 DNS劫持
DNS劫持的危害是非常大的,为了防止此情况,微信团队推出移动解析HttpDNS服务,避免Local DNS造成的域名劫持和跨网访问问题,这是一项付费服务。
DNS之后,第二个变量就是连接,小程序发送的请求会直接经过公网,通过网络的各个节点到达你的服务器所在地。
比如小程序用户在广州,你的服务器在北京,那么这个请求包会一路经过网络沿途的各个运营商交换中心的「路由节点」转发,一直到达你的服务器,这个过程中沿途受干扰变数较多,而且距离越远,变数越大。
当然解决办法也是有的,在全国各地布置接入点,每个接入点和服务中心直接拉专线网络,这叫私有专线;或者将服务端搬到各个地域,组成多地域服务;不管用什么方法,还是需要资金来建设。
# 二、微信链路请求
在微信小程序中,callContainer
方式的代码是这样子的:
const res = await wx.cloud.callContainer({
config: {
env: '填入云环境ID', // 微信云托管的环境ID
},
path: '/postapi', // 填入业务自定义路径和参数,根目录,就是 /
method: 'GET', // 按照自己的业务开发,选择对应的方法
header: {
'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
}
});
console.log(res);
但实际来讲,以上 callContainer
最终也是经过 wx.request
请求发出去的,但是走的却并不是常规的道路。(在WEB网页中是经过XHR发出的)
先说结论:callContainer
本质仍然是TCP请求,只是路径是微信的专有路径
在上一部分我们讲到DNS和公网的一些问题,在你使用 callContainer
发送请求的时候就已经全部解决了。
首先,DNS解析,通过 callContainer
发送请求时,小程序压根就不请求DNS解析,而是直接向微信服务器固定发送请求包,这个包中涵盖如下信息:
- 云托管环境ID(env)
- 云托管服务名称(service)
- 业务路径(path)
- 请求的数据(data)
这个请求包会直接经过就近节点进入微信遍布全国的专线网络,在就近地域内微信服务器中识别请求的内容,判断云托管环境ID在哪个地域,具体的地址是什么,然后向目标地址发送你的请求数据,并在这一过程中将用户的身份信息验证一下,带上用户的openid等其他身份信息。
当你云托管服务中收到请求时,header中就可以看到 x-wx
开头的微信认证信息,至于业务数据,和正常通过 wx.request
收到的数据一摸一样。
你的服务返回数据包,又会经过同样的路径返回,一直回到小程序中,第一次请求就结束了,这个时候除了服务器给的信息正常返回给你的前端业务层,还有一些信息在经过 callContainer
的时候被截留了。
这些截留的信息就是在第一次请求中,微信探查的「用户小程序」到「云托管服务」之间最佳的路径,以及加密的用户身份令牌。
之后发送请求的时候,callContainer
就会直接按照这个最佳路径发送请求包,而身份令牌可以在经过微信链路网关时被解析出来,最终以明文形式展示在服务header中。
而从 callContainer
经过 wx.request
发送请求,一直到收到回复,整个请求包都是经过端到端加密的,也就是说,即使用户的手机网络被抓包了,也是一堆加密信息,并没有什么可参考的价值。
另外在整个微信链路中,可以有效过滤网络攻击,恶意请求,刷接口等行为,这些请求都会在进入链路时就被过滤到,最终到达云托管服务时,都是经过微信验证的正常请求。
如果你的业务本身并不需要用户的身份信息,则可以在header中添加如下记录:
'X-WX-EXCLUDE-CREDENTIALS': 'unionid, cloudbase-access-token, openid'
以上是排除指令,如果不填写则会在链路通信中附带,填写则不附带。
因为附带信息会在占用一些时间(大概10ms-50ms),所以根据自己的业务需要,合理选择附带信息。
例子如下:
const res = await wx.cloud.callContainer({
config: {
env: '填入云环境ID', // 微信云托管的环境ID
},
path: '/postapi', // 填入业务自定义路径和参数,根目录,就是 /
method: 'GET', // 按照自己的业务开发,选择对应的方法
header: {
'X-WX-SERVICE': 'xxx', // xxx中填入服务名称(微信云托管 - 服务管理 - 服务列表 - 服务名称)
'X-WX-EXCLUDE-CREDENTIALS': 'unionid, cloudbase-access-token, openid' // 不附带用户unionid,openid,access—token
}
});
console.log(res);
# 三、 其他事项
- 当你使用未登录模式时,本身就没有用户信息,建议添加
X-WX-EXCLUDE-CREDENTIALS
能起到一定的加速作用。 - 未登录模式虽然没有用户信息,但是安全性和链路效率仍然有效存在。
- 除了云托管之外,云开发
callFunction
请求云函数的原理也基本类似。 - 在成本方面,
callContainer
的微信链路效果相当于WAF和DDOS高防叠加,在云托管服务中这些都是标准配置,无需你支付任何费用。 callContainer
不仅可以应用在微信云托管中,如果你自有的CVM服务器也需要这种链路服务优化,请在官方交流群联系我们,我们会根据你的业务情况提供最佳的解决方案。