无题
前两节我们学习了用 chrome 远程调试安卓移动端网页,用 safari 远程调试 ios 移动端网页:
那他们是怎么实现呢?
首先,我们知道调试是 client server 的架构,比如 chrome 会使用 CDP 协议来传输数据。
传递的 CDP 数据可以通过 Protocol monitor 看到:
pc 端是这样,移动端也是这样,只不过传递协议数据的方式不大一样。
要想起一个有 CDP server 的浏览器,需要单独指定一些参数。
pc 端是跑 chrome 的时候带上 remote-debugging-port 参数,类似这样:
1/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
然后就可以连上这个端口进行调试了,不管你是用 chrome devtools 还是 vscode debugger 或者其余的 frontend UI。
那移动端呢?
自然也是一样的,要开启调试模式才有这个 CDP Server 可以连接。
andor ...
无题
现在的网站基本都是 https 的,而 charles 是常用的 http 抓包工具,所以用 charles 调试 https 请求是常见的需求。
这节就来讲下如何用 charles 调试 https 请求,如何断点调试。
首先安装 charles,点击 start recording:
浏览器访问一些页面,这时候左侧就会展示出抓到的 http/https 请求:
但是这时候抓到的是加密过后的内容,这是 https 的机制导致的:
服务端会下发被 CA 认证过的证书,里面包含了公钥,而服务器自己保留私钥,通过这种机制完成对称密钥的传输和身份的认证,之后加密传输数据。
中间人拿到的数据自然都是被加密过的,也就是上图的那些乱码:
那抓包工具怎么能拿到明文的数据呢?
自己用服务端的证书和服务端对接不就行了?
也就是这样:
Charles 自己用服务端的证书来和服务端通信,然后给浏览器一个自己的证书,这样就能解密传输的内容,拿到明文数据了。
点击 Proxy 的 SSL Proxy Setting:
添加一条对 juejin 的 https 代理:
这是 juejin ...
无题
Charles 做为主流的代理工具,有很多强大好用的功能,这两节我们就快速过一遍:
charles 代理的两种配置方式网页默认是走系统代理。
可以把 Charles 也设置为系统代理,点击 Proxy > macOS Proxy 即可:
这样就能抓到网页的数据包了。
或者不把 charles 设置为系统代理,而是 SwitchyOmega 单独指定网页的代理服务为 charles:
这里的代理服务的端口可以在 Proxy > proxy Settings 里看到:
当然,更好的方式是 auto switch,也就是根据条件自动切换。
也就是我们在选项里配置的情景模式:
这两种还是很容易理解的:
默认都是走系统代理,所以把 charles 配置为系统代理服务器就可以抓包了
网页也可以通过 SwitchyOmega 单独指定代理服务器,这时候请求会直接走 charles
no caching可以让 http 请求禁用缓存,在 Tools > No Caching 里开启:
当开启之后,你会发现 header 会带上 cache-control: no-ca ...
无题
当线上有报错的时候,大家是怎么定位问题的呢?
断点调试么?
但是这时候代码是被压缩过的,变量名都是 a、b、c、d 这种,根本看不出啥来。
如果调试线上报错能像本地开发的时候一样就好了。
其实这是可以做到的,这节就分享下如何优雅的调试线上报错:
首先,我们准备一段 JS 代码:
这是我随便找的一段 JS 代码,里面抛了一个错误。
然后用 webpack 进行编译:
在 index.html 里引入构建产物:
然后跑个静态服务器 npx http-server .
浏览器访问,就会发现代码确实报错了:
那问题来了,怎么定位错误原因呢?
首先,我们可以使用异常断点,在抛异常的地方断住:
创建一个 vscode 调试配置:
勾选 uncaught exceptions,在未被捕获的异常处断住:
然后启动调试:
你会发现代码在抛异常的地方断住了,这就是异常断点的功能。当你不知道哪里抛的异常的时候,可以用这个。
但现在代码是被压缩过的,看不出啥来:
怎么能直接定位到抛异常的源码呢?
这时候就要用到 sourcemap 了,它就是用于把编译后的源码映射回源码的:
首先要生成 ...
无题
上节学了常用的代理功能,这节我们来学其他的 charles 功能:
DNS Spoofing在本地准备一个 index.html,然后 npx http-server . 来跑一个静态服务器:
浏览器访问下:
执行 sudo vim /etc/hosts 修改 hosts 文件,添加一条 www.guangguangtest.com 到 127.0.0.1 的映射:
之后就可以用这个域名来访问了:
(如果你把科学上网的工具设置为系统代理,hosts 可能就不生效了,关掉即可)
除了浏览器,在 Terminal 也是可以通过 curl 访问的:
ping 也能 ping 通:
charles 也有这个功能,叫做 DNS Spoofing(DNS 欺骗),在 Tools > DNS Spoofing 开启:
它的功能和 hosts 类似:
比如我配置了 www.guangguangtest2.com 的域名到 127.0.0.1 的映射,之后就可以浏览器访问这个域名了:
但在 Terminal 还不行:
为什么呢?
因为 DNS Spoofin ...
无题
前面学习了 Chrome DevTools 的各种工具的使用,从这节开始深入下它的实现原理。
调试工具都包含 frontend、backend、调试协议、信道这四个部分:
而在 Chrome DevTools 里这个调试协议就是 Chrome DevTools Protocol,简称 CDP。
打开 CDP 的文档,可以看到 CDP 协议分为了不同的 Domain:
比如 DOM、CSS、Debugger 等,这个很容易理解,各种工具的数据通信总不能混到一起吧,所以分成了不同的域来管理。
每个 Domain 下都包含了 Methods 和 Events:
Method 就是 frontend 向 backend 请求数据,backend 给它返回相应的数据
Event 就是 backend 推送给 frontend 的一些数据。
你可以在 Chrome DevTools 的设置里开启 Protocol Monitor 面板:
在 More Tools 里打开:
然后你就可以看到当前页面所有的 CDP 数据交互:
双向箭头的就是 Method,单向箭头的就是 backend ...
无题
上节我们把 chrome devtools frontend 跑起来,然后连上自己做的 CDP backend,实现了 network 面板、element 面板的对接,明白了 Chrome DevTools 的运行原理。
那我们能基于已有的 backend,自己实现 frontend 么?
当然也是可以的。
我们通过命令行的方式把 chrome 跑起来,通过 remote-debugging-port 指定 backend 的端口(这是 mac 下的 chrome 路径,windows 下的话大家自己找一下):
1/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
然后我们自己通过 WebSocket 客户端连上就可以了。
当然自己实现 CDP 的交互还是挺麻烦的,chrome 给提供了一个工具包 chrome-remote-interface,内部实现了和 CDP backend 的 WebSocket 通信,我们只需要调用它的 api 即可:
12 ...
无题
前面我们通过 npm 下载过 chrome devtools frontend 的代码:
1npm install chrome-devtools-frontend@1.0.672485
但是那个是比较老的版本,不需要 build。
如果想用新版本的 chrome devtools frontend,就需要下载源码自己 build 了。
这节我们一起来编译下 chrome devtools frontend 源码,并且做下修改,生成新的 chrome devtools。
下载 depot_toolschrome devtools frontend 有一套自己的工具链,我们先把这套工具链下载下来。
从 google code 下载即可(需要科学上网):
1git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
它有很多命令,我们要把它夹到环境变量里,这样就能直接用了:
1export PATH=/本地的路径/depot_tools:$PATH
我们会用到这个工具链的 fetch/gn ...
无题
Puppeteer 是一个网页的自动化测试工具,它支持写一些 JS 脚本来控制浏览器执行一些行为,可以用来跑测试用例,或者用来做爬虫。
它的脚本类似这样:
123456789101112131415161718192021222324const puppeteer = require('puppeteer');const fs = require('fs/promises');(async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://baidu.com'); const $input = await page.$('#kw'); await $input.type('guangguangguang'); const ...
无题
上一节我们实现了 Chromium 的自动下载,这节把 Chromium 跑起来,实现远程控制。
你是否好奇过 Puppeteer 的远程控制是怎么实现的呢?
其实也是基于 Chrome DevTools Protocol,它是 chrome devtools 和 chromium 通信的协议,chrome devtools 用它来获取 chromium 的一些信息,并且还可以控制 chromium 来做一些事情。
在 chrome devtools 里打开 Protocol Monitor,就可以看到 CDP 的数据:
chrome devtools 里展示的数据,控制浏览器执行一些行为,都是通过这个实现的,Puppeteer 也同样是基于这个。
在 CDP 的文档可以看到协议的详细描述:
它是分为不同的域的,比如 Page、Browser、Network 等,分区来管理不同的协议。
比如 Page.navigate 可以让页面导航到某个 url:
Page.close 可以关闭页面
Browser.close 可以关闭浏览器
Puppeteer 就是基于这些来远程控制 ...
