在Chrome扩展中拦截网络请求
While implementing the Chrome extension Mass Block Twitter, I needed to block Twitter spam users in bulk. Twitter's request headers contain authentication information that appears to be dynamically generated via JavaScript. Rather than investigating how Twitter generates these authentication details, I decided it would be more efficient to intercept existing network requests, record all headers being used, and then directly utilize these ready-made headers when calling the /i/api/1.1/blocks/create.json
endpoint. This created a need to intercept XHR requests. I had previously encountered situations requiring fetch request interception, and existing libraries couldn't adequately meet these requirements.
在实现 Chrome 扩展 Mass Block Twitter 时,我需要批量屏蔽 Twitter 垃圾用户。Twitter 的请求头包含的认证信息似乎是通过 JavaScript 动态生成的。与其调查 Twitter 如何生成这些认证细节,我决定拦截现有的网络请求,记录所有正在使用的头信息,然后在调用 /i/api/1.1/blocks/create.json
端点时直接利用这些现成的头信息。这就产生了拦截 XHR 请求的需求。我之前遇到过需要拦截 fetch 请求的情况,而现有的库无法充分满足这些要求。
Existing libraries I investigated include:
我调查的现有库包括:
- mswjs: A mocking library capable of intercepting XHR/fetch requests, but requires a service worker, which isn't possible for Chrome extension Content Scripts.
- mswjs:一个能够拦截 XHR/fetch 请求的模拟库,但需要服务工作者,这在 Chrome 扩展内容脚本中是不可能的。
- xhook: An interception library that can intercept XHR requests but not fetch requests. Additionally, its last update was two years ago, suggesting that it's no longer maintained.
- xhook:一个可以拦截 XHR 请求但不能拦截 fetch 请求的拦截库。此外,它的最后更新是在两年前,表明它不再维护。
Therefore, I decided to implement my own solution.
因此,我决定实现我自己的解决方案。
Design
设计
First, I considered my specific requirements:
首先,我考虑了我的具体需求:
- Intercept fetch/XHR requests
- 拦截 fetch/XHR 请求
- Support modifying request URLs to enable proxy requests
- 支持修改请求 URL 以启用代理请求
- Support invoking original requests and modifying responses
- 支持调用原始请求和修改响应
- Support SSE (Server-Sent Events) streaming responses
- 支持 SSE(服务器发送事件)流响应
After establishing these requirements, I began designing the API. Having previously used the excellent web framework hono, I wanted the API to be as simple ...