问题描述
我曾经使用另一个带有C#的代理服务器库来捕获HTTP请求,并且它只有一个AfterSessionComplete
事件,该事件在整个请求/响应操作都完成后才触发,您可以获取主机,路径和查询,请求和响应主体全部来自事件参数。但是,该库在某个时间之前停止了维护,因此我正在考虑切换到Titanium-Web-Proxy,并且似乎有一个AfterResponse
事件。这是我以前测试的内容:
private static async Task Server_AfterResponse(object sender,SessionEventArgs e)
{
try
{
Uri url = e.HttpClient.Request.RequestUri;
string method = e.HttpClient.Request.Method.toupper();
string req = e.HttpClient.Request.HasBody ? e.HttpClient.Request.BodyString : null;
string resp = e.HttpClient.Response.HasBody ? e.HttpClient.Response.BodyString : null;
ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
{
// Goes back to my old AfterSessionComplete method.
HttpProxy.AfterSessionComplete?.Invoke(url,method,req,resp);
}));
}
catch(Exception ex)
{
Debug.Print($"{ex}");
}
}
public static void Start(int port = 37123)
{
HttpProxy.server = new ProxyServer(false,false,false);
HttpProxy.server.AddEndPoint(new ExplicitProxyEndPoint(IPAddress.Any,port,false));
HttpProxy.server.AfterResponse += Server_AfterResponse;
HttpProxy.server.Start();
}
它不起作用。 HTTP流量将随机阻塞:Chrome DevTools中的未决状态表示某些请求不会触发AfterResponse
事件,最终超时。即使对服务器发出了请求,我也没有得到请求和响应主体,试图获取它们将触发诸如以下的异常:
System.Exception: You cannot get the request body after request is made to server.
System.Exception: Response body is not read yet. Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsstring() method to read the response body.
我也尝试了await GetRequestBodyAsstring()
和await GetResponseBodyAsstring()
,但还是没有。在那个阶段我很困惑,我该怎么办?我是否需要抛弃AfterResponse
并使用提供的其他事件?
解决方法
在Titanium中,AfterResponse事件标记了响应发送到浏览器的时刻(并且不再可用)。因此,要读取响应正文,您需要附加到BeforeResponse事件。此外,如您所见,您无法在*响应事件中访问请求正文。克服此限制的一种方法是使用UserData属性,并在BeforeRequest事件中保存以后可能需要的来自请求正文的所有数据。下面的示例代码显示了如何执行此操作:
void Main()
{
var proxyServer = new ProxyServer(userTrustRootCertificate: false);
proxyServer.BeforeRequest += OnBeforeRequest;
proxyServer.BeforeResponse += OnBeforeResponse;
var httpProxy = new ExplicitProxyEndPoint(IPAddress.Loopback,8080,decryptSsl: true);
proxyServer.AddEndPoint(httpProxy);
proxyServer.Start();
Console.ReadLine();
proxyServer.Stop();
}
// Define other methods and classes here
public async Task OnBeforeRequest(object sender,SessionEventArgs ev)
{
var request = ev.HttpClient.Request;
ev.UserData = request.HasBody ? await ev.GetRequestBodyAsString() : "";
}
public async Task OnBeforeResponse(object sender,SessionEventArgs ev)
{
var request = ev.HttpClient.Request;
var response = ev.HttpClient.Response;
var requestBody = (string)ev.UserData;
var responseBody = response.HasBody ? await ev.GetResponseBodyAsString() : "";
// TODO: Your old AfterSessionComplete method.
}