TSW 核心的实现方式是 Hack NodeJS 自身的 http.request
以及 http.createServer
, 以此来实现抓包机制。在服务器处理请求的前后,在服务器向其他服务器发包的前后,等等,都会有相应的事件抛出,以供用户来进行自定义处理。
为了让用户更加方便地复用、传播这样一组组自定义处理,我们将他们抽象出来,形成了插件机制。
export.modules = class MyPlugin() {
constructor() {
this.name = "MyPlugin"
}
async init(eventBus, config) {
eventBus.on("RESPONSE_CLOSE", (payload) => {
console.log(payload);
})
}
}
init
方法是必须的,这个方法在插件加载开始时会被调用,可以是同步也可以是异步。
eventBus
是通过 new EventEmitter()
得到的。TSW 核心会在各个关键时机触发上面的事件。
事件列表:
key | 含义(触发时机) | payload |
---|---|---|
DNS_LOOKUP_SUCCESS |
在每次 DNS 查询成功之后触发 | string | dns.LookupAddress[] |
DNS_LOOKUP_ERROR |
在每次 DNS 查询失败之后触发 | NodeJS.ErrorException |
RESPONSE_START |
在每次服务器开始返回响应(执行 writeHead )时触发 |
ResponseEventPayload |
RESPONSE_FINISH |
在响应结束时(res.on("finish") )触发 |
ResponseEventPayload |
RESPONSE_CLOSE |
在底层链接关闭时 (res.on("close") )触发 |
ResponseEventPayload |
REQUEST_START |
在每次服务器接受到新的请求时触发 | RequestEventPayload |
默认的情况下,TSW 只会把所有的日志和抓包内容抓取并且送到事件总线上,以供 插件 消费。所以将日志和抓包内容落地查看一般需要用户自己编写插件以及提供存储,使用成本过于高昂。
因此,TSW 官方提供了公共的服务平台( https://tswjs.org ), 让用户低成本、更快、更方便地使用 TSW 的特性。
appid
和 appkey
安装开放平台插件
yarn add @tswjs/open-platform-plugin
// npm i @tswjs/open-platform-plugin
在配置文件 tswconfig.js
中添加相关配置,具体参照 开放平台插件配置指引。
向之前启动的 Koa 或者原生 http server 发送请求,即可在开放平台上查看对应的日志和抓包。查看地址为下方地址拼接而成 https://${appid}.tswjs.org/log/view/${uid}
日志记录
在线查看抓包内容
const OpenPlatformPlugin = require("@tswjs/open-platform-plugin");
module.exports = {
plugins: [
new OpenPlatformPlugin({
appid: "***",,
appkey: "***",
reportStrategy: "proxied",
// 只支持同步写法
getUid: (request) => {
const cookie = request.headers.cookie;
if (!cookie) return;
const uid = /quid=([^;]*);?/g.exec(cookie);
return uid ? uid[2] : '';
},
// 同步或者异步函数
getProxyInfo: () => {
return {
"port": 80,
"name": "2.0demo",
"group": "TSW",
"groupName": "TSW团队",
"desc": "2.0demo测试环境",
"order": 30,
"owner": "demoUser",
"alphaList": ["demoUser"]
};
},
// 请求回调函数
hooks: {
// 请求开始前回调,返回 false 则提前返回
requestStart(payload) {
const { req, context } = payload
if (req.method === 'HEAD') return false
},
// 结束开始前回调,返回 false 则提前返回
responseFinish(payload) {
const { req, context } = payload
if (req.method === 'HEAD') return false
},
},
})
]
};
配置详解:
1.appid
String
项目在 TSW 开放平台 申请的应用 id。
2.appkey
String
项目在 TSW 开放平台 申请的应用 key。
3.reportStrategy
"always" | "never" | "proxied"
proxied
always
,表示在任何情况下都上报日志数据。
never
,表示在任何情况下都不上报日志数据。
proxied
,表示在被代理时上报数据。
4.getUid
() => string
同步函数() => {}
从每个请求中提取用户 uid
5.getProxyInfo
Function
同步或者异步函数() => {}
返回值如果为 undefined
,表示这台机器不被允许通过代理到达。
6.hooks.requestStart
Function
同步函数返回值如果为 false
,则不做 uid 提取和匹配检查。
7.hooks.responseFinish
Function
同步函数返回值如果为 false
,则跳过上报逻辑。
如果返回一个对象,那么根据对象参数不同有几种情况:
{
"port": 80,
"name": "2.0demo",
"group": "TSW",
"groupName": "TSW团队",
"desc": "2.0demo测试环境",
"order": 30,
"owner": "demoUser",
"alphaOnly": false,
"alphaList": ["demoUser"]
}
8.alphaOnly
false
false
,认为这台机器会被注册到开放平台上,可以通过在开放平台上配置代理到达。true
,认为这台机器只是负责染色号码以记录日志。不可从开放平台配置代理。一般生产环境开启此参数。9.alphaList
表示本机希望抓包的用户列表,值的比对对象是 getUid
方法返回值。
即 alphaList.includes(getUid())
。