易创云论坛

 找回密码
 立即注册
查看: 24890|回复: 0

推荐一个比FiddlerCore好用的HTTP(S)代理服务器

[复制链接]

170

主题

178

帖子

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
100700
发表于 2021-4-14 14:32:43 | 显示全部楼层 |阅读模式
原文连接:https://my.oschina.net/u/4391448/blog/4256997

为什么不用FiddlerCore?
说到FiddlerCore大家可能会比较陌生,那么它哥Fiddler就比较熟悉了;抓包、模拟低带宽、修改请求我平时比较常用。Fiddler的本质就是一个HTTP代理服务器。
FiddlerCore是Fiddler去除了UI的核心组件,可以用于二次开发。如下图所示:


Fiddler主要有以下几点感觉很别扭:
  • API命名不规范、属性/字段混用。
    .NET中普遍采用Pascal命名规范,而Fiddler的命名就像个大杂烩。例如:public成员用字段,CONFIG类名,oSession参数名
  • 不支持异步。所有的回调都是同步。
  • 框架设计不合理,不支持多实例,大量使用了静态方法。所有方法都堆到了Session类中不易于扩展,起码Request/Response也得分开啊。
单就以上几点我感觉这框架完全没有设计可言,如果没有别的选择FiddlerCore我或许就将就用了,好在Github上已经有人先一步重新实现了FiddlerCore
Titanium-Web-Proxy介绍
一个跨平台、轻量级、低内存、高性能的HTTP(S)代理服务器,开发语言为C#
功能特性
  • 支持HTTP(S)与HTTP 1.1的大部分功能
  • 支持redirect/block/update 请求
  • 支持更新Response
  • 支持HTTP承载的WebSocket
  • Support mutual SSL authentication
  • 完全异步的代理
  • 支持代理授权与自动代理检测
  • Kerberos/NTLM authentication over HTTP protocols for windows domain
使用
安装NuGet包
Install-Package Titanium.Web.Proxy
支持
  • .Net Standard 1.6或更高
  • .Net Framework 4.5或更高
设置HTTP代理
var proxyServer = new ProxyServer();//locally trust root certificate used by this proxy proxyServer.TrustRootCertificate = true;//optionally set the Certificate Engine//Under Mono only BouncyCastle will be supported//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;proxyServer.BeforeRequest += OnRequest;proxyServer.BeforeResponse += OnResponse;proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true){//Exclude HTTPS addresses you don't want to proxy//Useful for clients that use certificate pinning//for example dropbox.com// ExcludedHttpsHostNameRegex = new List<string>() { "google.com", "dropbox.com" }//Use self-issued generic certificate on all HTTPS requests//Optimizes performance by not creating a certificate for each HTTPS-enabled domain//Useful when certificate trust is not required by proxy clients// GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")};//An explicit endpoint is where the client knows about the existence of a proxy//So client sends request in a proxy friendly mannerproxyServer.AddEndPoint(explicitEndPoint);proxyServer.Start();//Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS//to send data to this endPointvar transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true){        //Generic Certificate hostname to use        //when SNI is disabled by client        GenericCertificateName = "google.com"};proxyServer.AddEndPoint(transparentEndPoint);//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };foreach (var endPoint in proxyServer.ProxyEndPoints)Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",    endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);//Only explicit proxies can be set as system proxy!proxyServer.SetAsSystemHttpProxy(explicitEndPoint);proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);//wait here (You can use something else as a wait function, I am using this as a demo)Console.Read();//Unsubscribe & QuitproxyServer.BeforeRequest -= OnRequest;proxyServer.BeforeResponse -= OnResponse;proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;proxyServer.Stop();
简单的请求与响应处理
//To access requestBody from OnResponse handlerprivate IDictionary<Guid, string> requestBodyHistory         = new ConcurrentDictionary<Guid, string>();public async Task OnRequest(object sender, SessionEventArgs e){    Console.WriteLine(e.WebSession.Request.Url);    ////read request headers    var requestHeaders = e.WebSession.Request.RequestHeaders;    var method = e.WebSession.Request.Method.ToUpper();    if ((method == "POST" || method == "PUT" || method == "PATCH"))    {        //Get/Set request body bytes        byte[] bodyBytes = await e.GetRequestBody();        await e.SetRequestBody(bodyBytes);        //Get/Set request body as string        string bodyString = await e.GetRequestBodyAsString();        await e.SetRequestBodyString(bodyString);                //store request Body/request headers etc with request Id as key        //so that you can find it from response handler using request Id          requestBodyHistory[e.Id] = bodyString;    }    //To cancel a request with a custom HTML content    //Filter URL    if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))    {        await e.Ok("<!DOCTYPE html>" +              "<html><body><h1>" +              "Website Blocked" +              "</h1>" +              "<p>Blocked by titanium web proxy.</p>" +              "</body>" +              "</html>");    }    //Redirect example    if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))    {        await e.Redirect("https://www.paypal.com");    }}//Modify responsepublic async Task OnResponse(object sender, SessionEventArgs e){    //read response headers    var responseHeaders = e.WebSession.Response.ResponseHeaders;    //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;    if (e.WebSession.Request.Method == "GET" || e.WebSession.Request.Method == "POST")    {        if (e.WebSession.Response.ResponseStatusCode == "200")        {            if (e.WebSession.Response.ContentType!=null && e.WebSession.Response.ContentType.Trim().ToLower().Contains("text/html"))            {                byte[] bodyBytes = await e.GetResponseBody();                await e.SetResponseBody(bodyBytes);                string body = await e.GetResponseBodyAsString();                await e.SetResponseBodyString(body);            }        }    }        //access request body/request headers etc by looking up using requestId    if(requestBodyHistory.ContainsKey(e.Id))    {        var requestBody = requestBodyHistory[e.Id];    }}/// Allows overriding default certificate validation logicpublic Task OnCertificateValidation(object sender, CertificateValidationEventArgs e){    //set IsValid to true/false based on Certificate Errors    if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)        e.IsValid = true;    return Task.FromResult(0);}/// Allows overriding default client certificate selection logic during mutual authenticationpublic Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e){    //set e.clientCertificate to override    return Task.FromResult(0);}
未来路线图
  • 支持HTTP 2.0
  • 支持Socks协议

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|易创云论坛 ( 吉ICP备17001024号-1 )

GMT+8, 2025-2-1 22:58 , Processed in 0.318055 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表