San DevTools 技术解析(中) #580
BUPTlhuanyu
started this conversation in
技术分享
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
San DevTools 技术解析(中)
文章导航
San-Devtools传送门
前言
我们已经分享了《San DevTools 技术解析》上篇,主要通过问题的方式,带着大家设计一款远程调试工具需要考虑的技术,并形成四大核心概念与模块,上篇中讲了其中两部分:
Backend
、Frontend
,今天重点来讲下剩余两部分:Message Channel
和DevTools Protocol
。这是非常有意思的话题。为帮助大家联系之前的内容,先放张上期的架构图。
消息通道(Message Channel)
整体架构
上图是非常核心的消息通信与运行机制流程图,我们先说明下其中的几个概念:
技术要点:
WebSocket 通信
简介
WebSocket 目前大多数浏览器都支持该协议。
WebSocket 协议标准将
ws
(WebSocket)和wss
(WebSocket Secure)定义为两个新的URI(统一资源标识符),分别对应明文和加密连接。WebSocket 协议可以使用 Chrome DevTools 等浏览器开发工具进行查看。
服务端实现
服务端的实现依赖于开源的
ws
。启动服务
WebSocket 是建立在 TCP 上的协议,通过 HTTP 协议的 101 状态码进行握手;HTTP 协议的 Header 增加
upgrade
的请求头,自动实现 HTTP 协议向 WebSocket 协议转换。关于握手协议,可以参考WebSocket维基百科Protocol handshake。握手成功后,需要手动调用
handleUpgrade
创建 Websocket 对象,建立连接。完整示例代码如下:通信信道
WebSocketServer
主要作用是提供WebSocket服务,frontend与backend分别联接WebSocket服务,建立对应的channel信道,并通过ChannelMultiplex进行信道管理与连接。ChannelMultiplex
主要负责管理 Channel 多信道通讯,分别按frontend和backend区分创建管理,创建frontend时,默认backend已经准备OK,这时去连接backend的Channel信道。Channel
主要作用是实现backend和frontend的两个ws信道对象之间的通信问题,Channel同时由fontend和backend实现,持有两个ws信道对象,实现从一个ws收到消息,再从另一个ws发送消息出去。重点理解
this.emit('message')
和connection.on('message')
两句话。注意在backend时,不会调用connect方法,内部不存在_connections。客户端实现
客户端不管是frontend还是backend,其本质都是运行在浏览器环境,都可以调用浏览器的
window.WebSocket
创建客户端连接。这里还有个比较重要概念
Bridge
,它是实现通信的桥梁,看下简化后的实现:可以看出
Wall
的实现里必须包含两个方法:listen和send,分别用于接收和发送事件。接下来看下Bridge的使用,frontend和backend的此处代码几乎一样:Extension 通信
浏览器插件开发,目前主要支持
Chrome
,接下来以Chrome插件为例进行介绍,Firefox
通信基本类似,API会不同。Chrome Extension 简介
关键技术点:
说明:
Chrome 插件中有三种通信模式:
window.postMessage
:短链接,适合在页面间通讯, Content Script 和 Inject Script;chrome.runtime.sendMessage
和chrome.tabs.sendMessage
:短链接,适合 background、panel、popup 等通信chrome.runtime.connect
和chrome.tabs.connect
:长链接,适合 background、panel、popup 等通信在 Chrome 扩展程序中可以使用
chrome.runtime.connect
创建一个长链接,每个长链接对应会有一个runtime.port
对象,可以利用该对象从长链接中接收/发送数据。为了管理各个长链接,可以监听
runtime.onConnect
事件,当扩展程序中其他部分通过chrome.runtime.connect
创建长链接的时候,会触发runtime.onConnect
事件,从该事件中可以获得刚创建的长链接对应的runtime.port
对象,可以利用该对象从长链接中接收/发送数据。Extension 通信实例
DevTools 扩展程序的 Backend 的实现如下:
content_script 的实现如下,主要建立 background 与 backend 之间的数据传输通道:
background 管理链接:
devtools_page 创建的 panel 中会创建一个长链接以及 bridge 实例,bridge 实例通过该长链接从 background 发送/接收消息。
调试器协议(DevTools Protocol)
简介
前后端接口交互有RestFul、GraphQL API接口风格定义,有接口规范文档约束字段定义等等接口协议方面的规则;具体业务前端后还会有接口文档。那调试器前后端要不要有协议方面的约束规则呢?显然是有必要的,这就是调试器协议主要解决的问题。
什么是调试器协议?调试器协议是通过定义调试工具(frontend)与被调试页面(backend)之间的交互协议,通过方法和事件提供双方的交互,包括相应的JSON数据格式的定义。其中交互协议包括被发送到页面的命令,和该页面生成的事件。
为了能够对协议的概念有个大概了解,我们简单演示下
Chrome DevTools
的协议。San DevTools
调试工具同时提供Chrome DevTools
和San DevTools
两种模式的远程调试能力,同时对应的有两种通信协议,分别介绍。San DevTools Protocol(SDP)
简介
类似于 Chrome 的协议, 我们定义支持了
San DevTools Protocol
交互协议,支持San应用的远程调试,制定规范约束前后端通信标准化。协议分为方法和事件两种类型,提供双方的交互,包括对应的JSON数据结构。Domain 设计
我们参考了 Chrome DevTools 协议,同样划分了多个Domain域的设计。
SDP Server
Hook 实现
Hook 主要用于监听
san.dev.js
调用 emit 触发的事件,是 backend 对san.dev.js
暴露的通信接口。执行 install 会在 san 应用的全局对象 target (比如 window) 上增加一个属性__san_devtool__
,该属性值是一个 Hook 实例,Hook 实例上存储了san
实例,组件树数据,store 实例,所有挂载的组件实例等。Agent 实现
Agent 是 backend 中数据处理模块,数据来源为 HOOK 收集的数据或者通过 Bridge 接收到的数据,处理之后的数据会通过 Bridge 发送出去抑或存储在目标页面。
Agent 类主要接收两个参数,一个是 Hook 实例一个是 bridge 实例,在实例化过程中主要执行 Agent 实例的两个方法:
更直观地,给出如下例子:
例子中的 setupHook 利用 hook.on 监听了
san.dev.js
触发的comp-*
事件,事件处理函数会将事件中拿到的组件实例 component 处理,将处理后的部分数据存储到 hook 实例的data
属性之后,调用 bridge.send 将数据发送给 messag channel 。例子中的 addListener 利用 bridge.on 监听了 message channel 传递过来的消息,消息处理函数则将 hook.data 上存储的数据发送给 message channel。
对于 Frontend 部分,没有 Hook 以及 Agent,数据流相对简单,只需要通过 bridge 实例监听 message channel 传递过来的数据,数据被处理之后通过响应式的 san 框架渲染到页面。通过 bridge.send 将页面中的数据发送给 message channel。
Chrome DevTools Protocol(CDP)
简介
Chrome 调试协议允许工具对 Chrome 和其他支持 WebSocket 的浏览器进行检测、检查、调试和分析。目前许多现有项目都使用该协议。Chrome 开发者工具使用这个协议,由它的团队维护API。
协议分为多个域(domain),比如DOM、Debugger、Network等。每个域定义了它支持的许多命令和它生成的事件。命令和事件都是固定结构的序列化JSON对象。
协议版本
官方的协议目前有四个版本:
CDP 实现
接下来我们看下协议如何在 San DevTools 落地实现的。
整体包括两部分:
CDP Server
和CDP Client
,San DevTools 中基于第三方库实现二者功能:liriliri/chobitsu 和 liriliri/chii。CDP Server
Chrome 浏览器是实现 CDP 协议最完整的,San DevTools 中为实现通用浏览器的远程调试,基于第三方远程工具,在前端页面实现了部分 CDP 协议。
原理:基于 JS 的数据收集,模拟实现部分 CDP 协议。
CDP Client
基于 CDP 协议的客户端常见两种:
我们分别进行演示:
CDP Client 实例
首先演示基于浏览器环境的 WebSocket,打开新页面并获取 Dom 树的例子,示例中涉及三个协议方法:
Node 调用协议实例
基于 Node 的 chrome-remote-interface 库。
示例同样演示打开新页面、获取Dom树,以及抓紧所有网络请求。
最后
感谢你阅读到了这里,以上便是《San DevTools 技术解析(中)》的全部内容。
San DevTools
除以上介绍的四大模块外,整个项目中还有很多非常有意思的技术,比如DevTools插件是怎么实现的;如何新增加一个Panel面板;插件开发是如何调试的;大型项目工程结构是怎么管理的等等。期待下期《San DevTools 技术解析(下)》再见!
Beta Was this translation helpful? Give feedback.
All reactions