最佳实践 | 使用 WebSocket 做个实时人脸活体比对服务
人脸核身产品为了提升用户体验、提高验证速度、提高验证过程中的安全性,会引入一些实时通信技术实时地提醒用户调整姿态,引导用户做活体动作,同时实时地做活体检测。人脸核身使用了两种实时通信技术——WebSocket 与 WebRTC。
本文将主要介绍一下,应用在人脸核身浮层活体中的 WebSocket。
浮层活体使用的核心技术——WebSocket
在浮层活体中,我们主打的特点就是“实时”——实时检测人脸距离、人脸遮挡等。在 WebSocket 诞生前,浏览器需要通过 HTTP 请求的方式去跟服务端索要数据。尽管后续的 HTTP 版本支持了或者聪明的开发者实现了各种“准实时”的索要数据的方案:轮询、长轮询、长连接等。但这些方式都离不开 Request/Response 对,即需要浏览器发起请求,服务器才有资格发送响应。
轮询与长轮询
最开始的“实时”并非真正的实时,而是由客户端每隔一段时间询问一下服务端是否有新数据产生,而客户端的轮询间隔决定了数据有多实时。
轮询的过程如下:
客户端发起请求
服务端马上响应,不论有无新数据。
等待 n 秒(即一个轮询间隔)后,客户端再次发起请求。
服务端依旧马上响应。
如此往复。
可以看到如果数据更新出现在两次轮询之间(一般来说,轮询间隔都是以秒为单位,所以数据几乎都会出现在两次轮询之间),那么最新的数据会经历一定的延迟才能送达。
于是,聪明的开发者就发明了一个长轮询方案。
长轮询的过程如下:
客户端发起请求。
服务端不马上响应,而是等待到数据更新到达后才响应客户端。(当然,一定的等待时间后还是没有数据更新的话也是会响应的。)
客户端处理响应后,马上发起下一个长轮询请求。
如此往复。
与轮询相比,长轮询的优势就在于,数据更新几乎没有延迟就能送达到客户端。同时也减少了客户端与服务端建立连接的次数,降低了连接建立的开销。
短连接与长连接
轮询与长轮询常常也会跟短连接长连接比较。总的来说,短链接就是每次请求都会建立一个新的 TCP 连接用于通信;而长连接则是多次请求复用同一个 TCP 连接。
然而,不论是短连接还是长连接、轮询还是长轮询,所有的数据更新均需要客户端发起请求索要,服务端方能发送。但是在浮层活体过程中,有很多数据更新是分批到达的,而且需要及时送达到客户端,所以需要一种更实时的通信方式。
WebSocket
WebSocket 为浏览器与服务端之间提供了一种双向通信的能力。与 Socket 类似,它是一种基于 TCP 连接的应用层协议。使用 HTTP 协议进行连接,连接建立成功后,双端就可以主动地向对方发送信息。
WebSocket 是怎么建立连接的?
借助 HTTP 协议,将 HTTP 所依赖的 TCP 连接抢到手,套上自己的面具,用自己的协议进行通信。
为了保持兼容 HTTP 服务端,WebSocket 选择使用 HTTP 协议来建立连接。首先,客户端会发送一个 HTTP Upgrade 请求,请求 upgrade 协议:
这就是一个很标准的 HTTP Get 请求的 Request。里面有一个关键的 Header:
Upgrade:upgrade 是 HTTP1.1 中用于定义转换协议的 header 域。它表示,如果服务器支持的话,把当前应用层协议切换一下,但是所基于的 TCP 连接不动。例如换成 WebSocket、HTTP2.0.
服务端收到一个协议切换请求后,就会自身能力做一个判断,如果支持该协议的话,就会回复一个 Upgrade 成功的 Response——Switching Protocols:
至此,这个 HTTP 所基于的 TCP 连接就被复用为 WebSocket 的连接了。下面就是一个 nodejs 版本的 websocket server demo。
由于 WebSocket 的连接建立需要依赖 HTTP 协议,所以有很多同学会误以为 WebSocket 是基于 HTTP 协议的一个协议。但实际上,WebSocket 在连接建立完成后,就跟 HTTP 没有任何关系了。它跟 HTTP 协议一样,都是基于 TCP 协议的一个应用层协议。
WebSocket 的帧格式
WebSocket 使用了自定义的二进制分帧格式,将每个应用消息切分成一个或多个帧,对端等到接收到完整的消息后再进行组装与处理。
主要介绍两个关键的字段:
FIN。占 1bit。表示后续是否还有帧。一个消息可能拆分成多个帧,接收方判断为最后一帧后将前面的帧拼接组成消息。TCP 没有粘包,粘包是不合理的应用层协议设计导致的问题。
opcode。占 4bit。
8 表示 close(关闭连接)帧,主动关闭连接时需要发送这个控制指令。否则 websocket 会报 1006 错误,这个错误码可以用于区分连接是正常关闭的,还是其他异常情况。
9 表示 ping 帧,10 表示 pong 帧。ping/pong 机制是为了在长时间无消息通信时,检测连接是否断开。目前只能由服务器发 ping 给浏览器,浏览器返回 pong 消息。浏览器目前没有开放发送控制指令的接口。
利用 WebSocket 实现一个简单的实时比对服务
我们可以简单地使用人脸检测与分析接口与人脸比对接口做一个实时的人脸检测与比对服务。
AI 能力方面,我们会使用到腾讯云提供的两个接口人脸检测与分析接口与人脸比对:
人脸检测与分析接口用于检测人脸位置与人脸遮挡,根据接口返回,提示用户调整姿态。
人脸比对接口用于对前端传入的截帧与服务端存储的比对照进行比对,得出一个相似度,用于判断是否同一人。
前端方面,我们使用getUserMediaAPI 打开摄像头用于获取视频流;使用WebSocketAPI 与服务端建立 WebSocket 连接。连接建立成功后,就可以从视频流中截取帧,发送到服务端进行检测。
服务端方面,我们可以用 Nodejs+ws这个 npm 包搭建一个简单的 WebSocket 服务端。服务端接到截帧之后就可以调用腾讯云提供的接口进行检测与验证。
体验浮层活体
人脸核身浮层活体也是基于上述方案实现的一个实时活体检测方案,同时还处理了更多的细节问题,让体验更丝滑。可以按照下面的步骤申请与体验人脸核身浮层活体服务。
1. 开通人脸核身服务
在腾讯云官网了解到 腾讯云AI 人脸核身 产品,点击申请免费试用即可体验。
2. 申请业务流程,获取 RuleId
人脸核身服务开通成功后,就可以到控制台创建业务流程:https://console.cloud.tencent.com/faceid
选择“微信 H5(浮层/普通模式)”,输入测试用的公众号名称后,点击下一步。
随后按控制台的提示填写相关信息。
申请完成之后,在控制台处查看自己的 RuleId。
3. 调用前置鉴权接口,获取体验连接
我们可以使用API Explorer来调用实名核身鉴权接口,获取体验连接。RuleId 入参填入上一步申请到的 RuleId。点击发起调用。
4. 用微信打开体验连接
调用 DetectAuth 接口成功后,回包中有一个 URL,使用微信打开,即可体验。
参考文档
版权声明: 本文为 InfoQ 作者【牵着蜗牛去散步】的原创文章。
原文链接:【http://xie.infoq.cn/article/e5983cb1c0d4594621ca9271d】。文章转载请联系作者。
评论