前两天逛V站,看到一个帖子《macos 抓包最佳实践是什么?》,这不是问到我的专业领域了嘛,赶紧点开看看。

这不巧了,用的正好是Reqable,找对工具就成功了80%,我心里好一阵开心,赶紧看看问题是什么。
1. 问题的场景
提问者的场景其实很简单,需要用Reqable抓下AI接口的调用数据。由于国外的几大AI巨头屏蔽了国内IP的访问,在抓包时,程序发起HTTP请求,会先访问Reqable,Reqable再访问AI接口服务器,这是一个代理的过程。但是Reqable并不具备科学上网的功能,所以这个访问会失败。解决方法正如提问者所说配置一个二级代理,让Reqable去访问Clash代理,Clash去访问AI接口的服务器,链路如下:
scss
client -> reqable(port:9000) -> clash(port: 7890) -> server
可以看出提问者的网络基础知识非常扎实,找到了正确的方式。接下来是他遇到的问题,浏览器上好使,但是在命令行里面跑程序就不好使了,原因和解决方案他也找到了:
第一个要在命令行里面配置代理环境变量,因为命令行并不会和浏览器一样自动读取系统代理配置,需要手动配置。
第二个是运行的程序不会读取命令行中配置的代理环境变量,还需要改代码强行走代理。从楼下的回复来看,应该是用的Javascript写的程序,需要加入如下代码,读取环境变量中的代理地址。
js
setGlobalDispatcher(
new ProxyAgent(process.env.HTTP_PROXY)
);
很明显,这个解决方案是临时的,非常繁琐不方便,所以他有了疑问:抓包最佳实践是什么?爱思考才能有进步,偷懒是科技进步的动力。
相信这个场景很多开发者都会遇到,我们也考虑过这个问题,并给出了解决方案:代理终端。
2. 代理终端如何用?
在Reqable顶部本机地址的后面有一个命令行图标,点击一下就可以打开代理终端了(快捷键 Alt + T)。

点击之后会打开一个命令行窗口,显示一个帅气的Reqable艺术照。

接下来,只需要直接在这个命令行里面正常运行程序就可以了,不需要配置环境变量,不需要修改代码,Everything is OK!
Reqable支持哪些命令行工具呢,有下面这些:
- Windows: cmd(默认)、PowerShell和Pwsh。
- Mac: Terminal(默认)、iTerm2。
- Linux: gnome console(Ubuntu)和konsole(KDE)、xterm。
注意:不用默认的命令行,可以图标右键点击修改默认启动的命令行工具。
为什么代理终端可以解决上面的两个问题呢,我们接下来揭晓答案。
3. 代理终端的原理是什么?
在启动命令行工具之后,我们会自动执行一段脚本,这个脚本做了下面几件事情。
首先,配置环境变量,把HTTP_PROXY和HTTPS_PROXY设置为Reqable的代理地址,例如 127.0.0.1:9000。
接着,修改PATH环境变量,在运行程序之前先执行我们预设好的程序进行Hook。比如要通过node执行一个JS程序,命令行从PATH中搜索node可执行程序的时候,由于我们的假node在PATH中位置最前面,就先找了这个假node,我们在其中先执行一段逻辑,例如强制网络框架走代理,强制不进行SSL验证等等,然后再调用系统真正的node来运行需要执行的程序。
sh
#!/bin/sh
set -e
# Find system node path
PATH="$(printf '%s\n' "$PATH" | sed "s:$(dirname "$0")\:::g")"
systemNode=`command -v node`
PATH="`dirname "$0"`:$PATH"
# Find the override script path
OVERRIDE_SCRIPT_PATH=`dirname "$0"`/override.js
# Call system node with the override script
"$systemNode" -r "$OVERRIDE_SCRIPT_PATH" "$@"
上面是一个shell脚本,在Windows上是bat脚本,内容大同小异。我们插入的逻辑在override.js里面,强制网络框架走代理。
js
const globalAgent = require("global-agent");
globalAgent.bootstrap();
// For node fetch usage
const Undici = require('undici');
const ProxyAgent = Undici.ProxyAgent;
const setGlobalDispatcher = Undici.setGlobalDispatcher;
setGlobalDispatcher(
new ProxyAgent(process.env.HTTP_PROXY)
);
最后一步,也是最关键的一步。输入一个帅气的Reqable艺术照,把逼格拉高。
sh
"echo '______ _ _ '",
"echo '| ___ \ | | | | '",
"echo '| |_/ /___ __ _ __ _| |__ | | ___ '",
"echo '| // _ \/ _` |/ _` | `_ \| |/ _ \'",
"echo '| |\ \ __/ (_| | (_| | |_) | | ___/'",
"echo '\_| \_\___|\__. |\__._|_.__/|_|\___|'",
"echo ' | | '",
"echo ' |_| '",
手敲上面这段是不可能的,我们找了一个text-to-ascii-art的网站自动生成。
上面是Node自动Hook的原理,而像Python又有很大的不同了,Python不是通过修改PATH环境变量来Hook,而是通过PYTHONPATH来指定路径Hook掉httplib、aiohttp等网络库,具体代码比较多,这里写不下,就不放出来了。
目前Reqable代理终端支持NodeJS、Python和Ruby三种程序的强制代理,当前其他的不需要强制代理的也可以使用。如果大家有其他需要支持的或者方案实现,欢迎在评论区一起讨论交流。
4. 我在反思什么?
这么好用的功能为什么大家都不知道,这个问题不得不引起我的反思。说明,我们的文档和教程做得不够好不够细,后面要大大加强这方面的建设。
感谢大家的阅读,欢迎体验我们的产品:
未来属于Reqable!