正文从这开始~~
身为每天都要与网页打交道的前端工程师,熟悉 DevTools 的使用是相当合理的。每当接 API 出问题时,就按下快捷键打开 DevTools,切到 Network 分页,找到红色的那一行,右键复制成 cURL 粘贴到群里面,让后端自己找找问题。
但不知道大家有没有碰过 DevTools 不够用的情况,这时该怎么办?
DevTools 真的会不够用吗?是不是你不会用?
举几个我实际碰过的案例,如果 DevTools 能解决那当然是最方便的,但我解决不了(也有可能是我不会用就是了)。另外,下面的 DevTools 指的都是 Chrome DevTools,或许其他浏览器的不会有这些问题。
重定向前的请求细节看不到
很多实现 OAuth 相关服务的网站在登录完成后,会跳转到 redirect url 并且带着一个 code,而这时有些网站会拿 code 去交换 access_token,然后再带着 access_token 跳转到下一个页面。如果 code 交换 access_token 这一步有问题,该怎么 debug 呢?
Chrome DevTools 在跳转到其他页面时,默认会把 console 和 network 的东西都清空。有一个选项叫做「Preserve log」,把它勾起来以后看似问题就解决了,但其实没有。
大家可以随便找一个网页,打开 DevTools 并且把保留 log 勾起来,然后执行以下代码:
fetch('https://httpbin.org/user-agent')
.then(()=> window.location ='https://example.com')
当跳转完成以后,虽然 Network 那边确实可以看到这个请求,但点进去以后只会看到「Failed to load response data」:
看不到请求
这个问题从 2012 年就有人反馈了,好不容易等了十几年,2023 年底时说这个在 2024 的 roadmap 上,但目前依然没有任何动静:DevTools: XHR (and other resources) content not available after navigation。
这个问题的本质是:一旦页面跳转,旧页面的 Network 请求数据就会被浏览器丢弃。因此即使请求已经发送,DevTools 也无法保留或查看 Response。
总之呢,在这个情境之下,看不到 response 基本上没办法 debug,很不方便。
WebSocket 连接握手失败找不到原因
虽然我们平常在用 WebSocket 时,只需要一行代码就可以建立连接,但背后其实是分了两步。
第一步会发出一个 HTTP Upgrade 请求,完成以后才切换到 WebSocket 连接。虽然大多数情况下第一步都会成功,那如果第一步失败会怎样呢?
我们可以请 AI 写一个很简单的 demo 出来:
写一个 nodejs websocket server,然后用一个 nginx 挡在前面 nginx 的作用是当 url 含有?debug 的时候要返回 500 错误 当 websocket 连接后会往 client 自动发送 hello 的 message 最后要包装成可以用 docker compose 跑起来
等 AI 生成完之后用 docker 跑起来,一样随便开个网页建立连接,会发现带有 debug 的那个连接请求,你只知道失败了,却完全不知道原因:
看不到原因
这个错误信息甚至跟你随便连一个没开的端口一样,完全不知道为什么会失败,这样也很难跟后端说问题在哪里。
其实遇到 WebSocket 握手失败,也可以尝试用其他方式辅助调试,比如用 curl -i --include
手动模拟 HTTP Upgrade 请求,检查是不是被后端或代理服务器拦截。这在无法获取浏览器详细错误信息时,是个不错的替代方案。
【第1882期】基于Unix Socket的可靠Node.js HTTP代理实现(支持WebSocket协议)
以上是两个我有印象的范例,但实际开发中应该碰过更多更多,基本上都是只靠 DevTools 来看 Network 没办法解决的问题,要么是看不到,要么看到的东西不太对。
简单好用的 HTTP Proxy
既然没办法靠 DevTools,那只能依赖更底层的工具了,比如说 HTTP Proxy!有些工具会在你本机起一个 proxy,这样流量就会都经过它,自然而然就能看到所有的请求了,就不必再受限于 DevTools。
HTTP Proxy 就像是你和网站之间的一个中继站:所有流量会先到 Proxy,再转给目标服务器。这样就能完整拦截、查看、甚至修改请求与响应内容。这也是为什么 Proxy 能突破浏览器 DevTools 的限制,直接拿到你想要的原始数据。
而且另一个好处是有地方可以互相对照,如果 proxy 显示的跟 DevTools 显示的不同,就有可能是 DevTools 显示的东西有问题。
因此,诚心推荐大家找个 HTTP Proxy 来用,我自己用过的有这三个:
Charles Burp Suite mitmproxy
以前我刚接触 proxy 时用的是 Charles,接触到安全测试以后就改成用第二个 Burp Suite 了。它其实是个可以拿来做各种安全相关测试的工具,但我觉得你只拿来做 proxy 也没问题,非常方便。
第三个 mitmproxy 是开源且免费的,知名度也很高,我偶尔也会用但是用的方式不太一样,这个晚点再讲。
把 Burp Suite 当 Proxy App 来用
先到官网下载安装免费的社区版:https://portswigger.net/burp/communitydownload
打开之后按下 Next 然后 Start Burp,就会看到主画面。你会发现它的功能很多,但我们先切到「Proxy」标签下「HTTP history」这一页就行了:
Burp 画面
然后那颗很显眼橘色的「Open Browser」点下去,就会开启它自带的 Chrome 浏览器,可以用这个浏览器访问任何一个网页,例如说 example.com。
接着切回工具,就会发现 HTTP history 里面记录着所有请求的原始内容和 response:
请求记录
如此一来,前面提过的跳转案例跟 WebSocket 握手失败,都可以在这边看到原始请求内容,错误一目了然:
原始内容
如果未来你碰到有些请求看不到,那就是被默认的 filter 筛选掉了,点 Filter settings 那边选 show all 后 apply,应该就能看到了。
若是有碰到不安全的连接等问题,需要先安装证书,请参考:Installing Burp’s CA certificate
以上就是 Burp Suite 作为 HTTP Proxy 的基本介绍。如果你不想用它提供的 Chrome,也可以自己设置电脑或是浏览器的 proxy,它默认会在 8080 端口。
举例来说,我在 Mac 上会再装一个 Chrome Canary 专门拿来 debug,用这个指令可以开启并且设置好 proxy 位置:
open -a "Google Chrome Canary" --args --proxy-server="http://localhost:8080"
如此一来就能用自己熟悉的浏览器 debug 了。
话说 Burp Suite 还有很多其他功能啦,比如说重放请求或是暴力破解等等,不过我觉得一般工程师把它当 proxy 来用就已经帮助很大了。对完整功能有兴趣的话可以参考 HackerCat 所写的《Web 渗透测试 – Burp Suite 完整教学系列》。
用 mitmproxy 搭配脚本动态改变内容
mitmproxy 的安装过程我就不多说了,可以参考官方文档或是跟 AI 协作自己装起来,安装完之后也记得访问一下 http://mitm.it 下载并安装证书,才能拦截到 HTTPS 的流量。
都安装完以后,执行 mitmproxy
就能够把 proxy 跑起来了,会看到一个 CLI 的界面。
那既然 Burp Suite 已经很好用了,什么时候会用到 mitmproxy 呢?它有个好用的功能是可以通过简单的 Python 脚本去自定义 proxy 的行为,非常方便。
举例来说,假设因为某些原因,测试环境无法完全模拟正式环境,但你又不可能直接把代码上线到正式环境去测试。这时就可以用 proxy 动态替换 production 的 response,在本地模拟一些行为。
虽然 Chrome 也有覆盖 response 的功能,但限制比较多,比如说内容只能固定等等。我们自己用 proxy 搭配脚本,绝对是更灵活而且自由度更高的选择。
下面是一个简单的 mitmproxy 脚本,目的是把我博客的 script.js 用本地的来替换:
from mitmproxy import http
import requests
URL_MAPPINGS={
"https://blog.huli.tw/js/script.js":"http://localhost:5555/script.js",
}
def request(flow: http.HTTPFlow)-> None:
for url inURL_MAPPINGS:
if flow.request.pretty_url.startswith(url):
replacement_url =URL_MAPPINGS[url]
replacement_response = requests.get(replacement_url)
flow.response = http.Response.make(
200,
replacement_response.content,
{"Content-Type":"application/javascript"}
)
return
用这个指令就可以跑起来:
mitmproxy -s proxy.py
接着用前面讲过的指令打开一个设置好代理服务器的浏览器:
open -a "Google Chrome Canary" --args --proxy-server="http://localhost:8080"
再用浏览器访问 https://blog.huli.tw,就能够看出 script 的内容已经被替换。
结语
以上就是我平常自己会使用到的一些代理服务器以及使用方法。
太过依赖于浏览器不是件好事,只要浏览器没有显示,就不知道该怎么办。但前端工程师作为第一线,绝对是有办法拿到整个 request 与 response,才能进一步厘清问题。以后如果碰到浏览器上看不到请求的问题,可以试试看使用代理服务器来拿到完整的请求以及响应。
除了电脑的网页之外,手机也可以使用,可以在 Android 上设置代理服务器连接到同一个 Wi-Fi 的电脑上,接着在手机上安装证书,就能够拦截手机的流量。
最后再讲一个小技巧,在 Mac 的命令行执行指令时加上:
https_proxy=http://localhost:8080
就能够配置代理服务器,比如:
https_proxy=http://localhost:8080 cursor
就可以把 Cursor IDE 的流量都导到代理服务器去。

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!
优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、DIY体验、720全景展厅及3D虚拟仿真)、移动端应用(手机站、APP开发)、微信定制开发(微信官网、微信商城、企业微信)、微信小程序定制开发等一系列互联网应用服务。