概述
在web開發(fā)境析,測試以及性能優(yōu)化,數(shù)據(jù)抓包時(shí),常會(huì)借助一此工具翼岁,幫助我們更好地理解和控制網(wǎng)絡(luò)通信過程。
本文提供兩個(gè)工具FiddlerCore
和TitaniumProxy
的實(shí)現(xiàn)方式以及示例代碼司光,分享幾個(gè)數(shù)據(jù)抓包的實(shí)際案例琅坡,供大家參考。
FiddlerCore
簡介
FiddlerCore是一個(gè)強(qiáng)大的庫残家,允許你使用C#攔截榆俺、修改HTTP(Https)和WebSocket流量。
它主要有以下一些特點(diǎn)和功能:
網(wǎng)絡(luò)抓包:可以捕獲瀏覽器與服務(wù)器之間的 HTTP/HTTPS 請求和響應(yīng)坞淮。
請求分析:詳細(xì)查看請求的各種信息茴晋,如請求頭、請求體回窘、響應(yīng)頭诺擅、響應(yīng)體等。
模擬請求:能夠手動(dòng)創(chuàng)建和發(fā)送自定義請求啡直。
調(diào)試會(huì)話:方便對網(wǎng)絡(luò)交互進(jìn)行故障排查和調(diào)試烁涌。
篡改請求和響應(yīng):在測試和開發(fā)中可臨時(shí)修改數(shù)據(jù)。
Fiddlercore攔截Https的原理是自己創(chuàng)建一個(gè)Https的證書酒觅,重新對網(wǎng)站的鏈接數(shù)據(jù)進(jìn)行加密傳輸撮执,所以,我們要通過代碼創(chuàng)建一個(gè)https證書給Fiddlercore舷丹。
https的處理過程需要一個(gè)自簽名證書:
創(chuàng)建Https證書有兩種方式抒钱,一種是通過MakeCert.exe ,另一種是通過 CertMaker.dll及BCMakeCert.dll來創(chuàng)建。
在官網(wǎng)說明中谋币,明確的說了兩點(diǎn):
1仗扬、MakeCert.exe使用Windows API生成存儲(chǔ)在用戶的\Personal\Certificates存儲(chǔ)中的證書。這些證書與iOS設(shè)備不兼容瑞信,后者需要證書中未由MakeCert.exe設(shè)置的特定字段厉颤。
2、CertMaker.dll使用BouncyCastle C#庫(BCMakeCert.dll)從頭開始生成新證書凡简。這些證書僅存儲(chǔ)在內(nèi)存中逼友,并與iOS設(shè)備兼容。
我們 在Fiddlercore編程的時(shí)候秤涩,通常采用dll方式創(chuàng)建證書帜乞,創(chuàng)建后的證書放在內(nèi)存中。所以筐眷,僅當(dāng)程序第一次啟動(dòng)的時(shí)候黎烈,我們才需要?jiǎng)?chuàng)建證書,以后再啟動(dòng)程序匀谣,就不需要?jiǎng)?chuàng)建證書了照棋,這個(gè)過程持續(xù)到電腦重啟為止。
FiddlerCoreStartupSettingsBuilder
的配置方法如下:
常用設(shè)置包括:
·ListenOnPort(int):指定FiddlerCore將偵聽的端口武翎。若設(shè)置為0烈炭,則表示隨機(jī)分配端口。
·AllowRemoteClients():允許FiddlerCore接受來自當(dāng)前機(jī)器外部的請求宝恶,例如遠(yuǎn)程計(jì)算機(jī)和設(shè)備符隙。在允許遠(yuǎn)程客戶端連接到FiddlerCore時(shí)需謹(jǐn)慎,因?yàn)楣粽呖赡芡ㄟ^該FiddlerCore實(shí)例代理其流量垫毙,從而繞過IPSec流量規(guī)則和內(nèi)部網(wǎng)防火墻霹疫。系統(tǒng)代理設(shè)置方面,有多種可能需要修改以適應(yīng)合適代理設(shè)置的系統(tǒng)和連接類型综芥,在此只處理最常見場景丽蝎。對于更高級的代理配置,請參閱注冊為系統(tǒng)代理文章膀藐。
RegisterAsSystemProxy()可修改本地局域網(wǎng)連接的代理設(shè)置屠阻,使其指向FiddlerCore在本地主機(jī)上監(jiān)聽的端口。
MonitorAllConnections()可修改所有系統(tǒng)連接的代理設(shè)置消请,使其指向FiddlerCore在本地主機(jī)上偵聽的端口。
CaptureFTP()可修改系統(tǒng)中與ftp相關(guān)聯(lián)的代理設(shè)置类腮,使其指向FiddlerCore在本地主機(jī)上偵聽的端口臊泰。HookUsingPACFile()可修改當(dāng)前使用PAC文件配置方式進(jìn)行網(wǎng)絡(luò)連接時(shí)所使用到的代理設(shè)置。同時(shí)蚜枢,F(xiàn)iddlerCore還提供了一個(gè)PAC文件用于調(diào)整網(wǎng)絡(luò)連接缸逃,在服務(wù)默認(rèn)PAC文件時(shí)可以通過更改“fiddler.proxy.pacfile”進(jìn)行配置右蹦,默認(rèn)情況下它包含了FindProxyForURL(url, host)函數(shù)體等內(nèi)容:"
FiddlerCore
是一個(gè) .NET 類庫舍败,沒有界面,您可以將其集成到您的 .NET 應(yīng)用程序中。它提供 .NETCore、.NET Framework版本挖腰,官方收費(fèi),我提供了一個(gè)免費(fèi)版本5.0.2忙干,直接在項(xiàng)目中使用辕翰。
以下以.netcore版本為例,FiddlerCore5.0.2
版本 項(xiàng)目中引用FiddlerCore
庫
安裝證書
//加v runsoft1024提供源碼
static bool InstallCertificate()
{
FiddlerApplication.Log.LogString($"安裝證書,為了監(jiān)聽https請求");
if (!CertMaker.rootCertExists())
{
if (!CertMaker.createRootCert())
return false;
if (!CertMaker.trustRootCert())
return false;
}
return true;
}
卸載證書
static bool UninstallCertificate()
{
if (CertMaker.rootCertExists())
{
if (!CertMaker.removeFiddlerGeneratedCerts(true))
return false;
}
return true;
}
創(chuàng)建代理
static void StartupFiddler()
{
// Attach to events of interest:
FiddlerApplication.AfterSessionComplete += session => Console.WriteLine(session.fullUrl);
//Build startup settings:
var settings = new FiddlerCoreStartupSettingsBuilder()
.ListenOnPort(9898)
.RegisterAsSystemProxy()
.DecryptSSL()
.OptimizeThreadPool() //啟用多線程
.AllowRemoteClients() //websocket open
.Build();
CONFIG.EnableIPv6 = true; //websocket open
CONFIG.IgnoreServerCertErrors = true;
// Start:
FiddlerApplication.Startup(settings);
FiddlerApplication.Log.LogString($"Created endpoint listening on port {CONFIG.ListenPort}");
}
關(guān)閉代理
static void UninstallFiddler()
{
if (FiddlerApplication.IsStarted())
{
FiddlerApplication.Shutdown();
}
}
處理事件
//攔截請求與響應(yīng)事件
static void AttachListening()
{
//FiddlerApplication.OnNotification += (o, nea) => Console.WriteLine($"** NotifyUser: {nea.NotifyString}");
FiddlerApplication.Log.OnLogString += (o, lea) => Console.WriteLine($"** LogString: {lea.LogString}");
FiddlerApplication.OnWebSocketMessage += FiddlerApplication_OnWebSocketMessage;
FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
FiddlerApplication.BeforeResponse += FiddlerApplication_BeforeResponse;
}
websocket處理
FiddlerApplication.OnWebSocketMessage += FiddlerApplication_OnWebSocketMessage;
static void FiddlerApplication_OnWebSocketMessage(object? sender, WebSocketMessageEventArgs e)
{
//編寫業(yè)務(wù)邏輯
var payload = e.oWSM.PayloadAsBytes();
var txt = Utilities.ByteArrayToString(payload);
var s = e.oWSM.PayloadAsString();
e.oWSM.SetPayload(payload);
}
http請求事件
FiddlerApplication.BeforeRequest += FiddlerApplication_BeforeRequest;
static void FiddlerApplication_BeforeRequest(Session oSession)
{
//為了啟用響應(yīng)篡改,緩沖模式必須被啟用挪丢;
//這允許FiddlerCore允許修改BeforeResponse處理程序中的響應(yīng),而不是流式傳輸響應(yīng)進(jìn)來時(shí)對客戶端的響應(yīng)蹂风。
oSession.bBufferResponse = false;
//只監(jiān)聽目標(biāo)網(wǎng)站
if(!oSession.fullUrl.Contains("rscode.cn"))
{
return;
}
// 如果您希望FiddlerCore通過以下方式自動(dòng)進(jìn)行身份驗(yàn)證,請?jiān)O(shè)置此屬性
// answering Digest/Negotiate/NTLM/Kerberos challenges itself
//session["X-AutoAuth"] = "(default)";
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(String.Format("{0} {1}", oSession.RequestMethod, oSession.fullUrl));
//header
Console.ForegroundColor = ConsoleColor.White;
for (int i = 0; i < oSession.RequestHeaders.Count(); i++)
{
var s=String.Format("{0,-20}{1}", oSession.RequestHeaders[i].Name, oSession.RequestHeaders[i].Value);
FiddlerApplication.Log.LogString($" {s}");
}
//body
if(oSession.RequestBody!=null)
{
// var s= Encoding.UTF8.GetString(oSession.RequestBody);
var s=oSession.GetRequestBodyAsString();
FiddlerApplication.Log.LogString($" {s}");
}
}
http響應(yīng)事件
FiddlerApplication.BeforeResponse += FiddlerApplication_BeforeResponse;
/// <summary>攔截請求返回Response信息</summary>
static void FiddlerApplication_BeforeResponse(Session oSession)
{
//只監(jiān)聽目標(biāo)網(wǎng)站
if (!oSession.oRequest.host.Contains("rscode.cn"))
{
return;
}
if(oSession.ResponseHeaders.Count()>0)
{
Console.ForegroundColor = ConsoleColor.White;
for (int i = 0; i < oSession.ResponseHeaders.Count(); i++)
{
var s=String.Format("{0,-20}{1}", oSession.ResponseHeaders[i].Name, oSession.ResponseHeaders[i].Value);
FiddlerApplication.Log.LogString($" {s}");
}
}
if (oSession.ResponseBody != null)
{
Console.ForegroundColor = ConsoleColor.White;
var s = oSession.GetResponseBodyAsString();
FiddlerApplication.Log.LogString($" {s}");
}
}
運(yùn)行Fiddler
void FiddlerStart()
{
FiddlerApplication.Log.LogString($"啟動(dòng)程序...");
//安裝證書
InstallCertificate();
//攔截http請求信息事件
AttachListening();
//啟動(dòng)Fiddler
StartupFiddler();
Console.WriteLine("按任意鍵結(jié)束本地代理監(jiān)聽..." + Environment.NewLine);
Console.Read();
//卸載證書
UninstallCertificate();
//關(guān)閉Fiddler
UninstallFiddler();
}
以上代碼展示了從創(chuàng)建證書乾蓬,啟動(dòng)fiddler,監(jiān)聽請求與響應(yīng)惠啄,關(guān)閉fiddler的全過程,不明白還可以查閱FiddlerCore官方文檔
TitaniumProxy
簡介
TitaniumProxy 是一個(gè)跨平臺(tái)任内、輕量級撵渡、低內(nèi)存、高性能的HTTP(S)代理服務(wù)器死嗦,開發(fā)語言為C#,常用于抓包趋距、模擬低帶寬、修改請求等場景越走。
功能特性
- 支持HTTP(S)與HTTP 1.1的大部分功能
- 支持redirect/block/update 請求
- 支持更新Response
- 支持HTTP承載的WebSocket
- Support mutual SSL authentication
- 完全異步的代理
- 支持代理授權(quán)與自動(dòng)代理檢測
- Kerberos/NTLM authentication over HTTP protocols for windows domain
實(shí)現(xiàn)步驟
以下是使用Titanium.Web.Proxy
實(shí)現(xiàn)HTTP代理服務(wù)器的基本步驟:
- 安裝
Titanium.Web.Proxy
庫棚品; - 創(chuàng)建代理服務(wù)器,并設(shè)置基本配置廊敌;
- 響應(yīng)事件處理铜跑,可以根據(jù)需要進(jìn)行自定義;
- 添加終結(jié)點(diǎn)骡澈;
- 啟動(dòng)代理服務(wù)器锅纺,并設(shè)置為系統(tǒng)代理。
如果你在使用Titanium.Web.Proxy過程中遇到問題肋殴,可以參考相關(guān)文檔或社區(qū)帖子囤锉,也可以嘗試搜索其他解決方案。
創(chuàng)建代理
using System.Net;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
var proxyServer = new ProxyServer();
創(chuàng)建證書
// 此代理使用的本地信任根證書
//proxyServer.CertificateManager.TrustRootCertificate = true;
//proxyServer.CertificateManager.TrustRootCertificate(true);
//使用BouncyCastle庫來生成證書
proxyServer.CertificateManager.CertificateEngine = Titanium.Web.Proxy.Network.CertificateEngine.DefaultWindows;
proxyServer.CertificateManager.EnsureRootCertificate();
//在Mono之下护锤,只有BouncyCastle將得到支持
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
proxyServer.CertificateManager.SaveFakeCertificates = true;
proxyServer.CertificateManager.RootCertificate = proxyServer.CertificateManager.LoadRootCertificate();
if (proxyServer.CertificateManager.RootCertificate == null)
{
Console.WriteLine("正在進(jìn)行證書安裝官地,需要安裝證書才可進(jìn)行https解密,若有提示請確定");
proxyServer.CertificateManager.CreateRootCertificate();
}
添加端點(diǎn)
顯式端點(diǎn)
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{
// 在所有https請求上使用自頒發(fā)的通用證書
// 通過不為每個(gè)啟用https的域創(chuàng)建證書來優(yōu)化性能
// 當(dāng)代理客戶端不需要證書信任時(shí)非常有用
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
};
// 顯式端點(diǎn)是客戶端知道代理存在的地方,因此烙懦,客戶端以代理友好的方式發(fā)送請求
proxyServer.AddEndPoint(explicitEndPoint);
透明端點(diǎn)
透明endpoint 對于反向代理很有用(客戶端不知道代理的存在); 透明endpoint 通常需要一個(gè)網(wǎng)絡(luò)路由器端口來轉(zhuǎn)發(fā)HTTP(S)包或DNS發(fā)送數(shù)據(jù)到此endpoint
var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true)
{
// 客戶端禁用SNI時(shí)要使用的通用證書主機(jī)名
GenericCertificateName = "google.com"
};
proxyServer.AddEndPoint(transparentEndPoint);
處理事件
添加事件
proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback;
proxyServer.BeforeRequest += ProxyServer_BeforeRequest;
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += ExplicitEndPoint_BeforeTunnelConnectResponse;
proxyServer.AddEndPoint(explicitEndPoint);
處理事件
async Task<bool> OnBeforeTunnelConnect(string hostname)
{
if (hostname.Contains("rscode.cn"))
{
//排除rscode.cn被解密驱入,而是通過安全的TCP隧道中繼
return await Task.FromResult(true);
}
else
{
return await Task.FromResult(false);
}
}
async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
await Task.Run(() =>
{
string hostname = e.HttpClient.Request.RequestUri.Host;
if (hostname.Contains("rscode.cn"))
{
// 排除您不想代理的Https地址
// 對于使用證書固定的客戶端很有用
// 例如本例 dropbox.com
e.DecryptSsl = false;
}
});
}
async Task OnRequest(object sender, SessionEventArgs e)
{
Console.WriteLine(e.HttpClient.Request.Url);
// read request headers
var requestHeaders = e.HttpClient.Request.Headers;
var method = e.HttpClient.Request.Method.ToUpper();
if ((method == "POST" || method == "PUT" || method == "PATCH"))
{
// Get/Set request body bytes
byte[] bodyBytes = await e.GetRequestBody();
e.SetRequestBody(bodyBytes);
// Get/Set request body as string
string bodyString = await e.GetRequestBodyAsString();
e.SetRequestBodyString(bodyString);
// store request
// 這樣你就能從響應(yīng)處理器中找到它
e.UserData = e.HttpClient.Request;
}
// 取消帶有自定義HTML內(nèi)容的請求
// Filter URL
if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("rscode.cn"))
{
e.Ok("<!DOCTYPE html>" +
"<html><body><h1>" +
"Website Blocked" +
"</h1>" +
"<p>Blocked by titanium web proxy.</p>" +
"</body>" +
"</html>");
}
// Redirect example
if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
{
e.Redirect("https://www.paypal.com");
}
}
// Modify response
public async Task OnResponse(object sender, SessionEventArgs e)
{
// read response headers
var responseHeaders = e.HttpClient.Response.Headers;
//if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return;
if (e.HttpClient.Request.Method == "GET" || e.HttpClient.Request.Method == "POST")
{
if (e.HttpClient.Response.StatusCode == 200)
{
if (e.HttpClient.Response.ContentType != null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html"))
{
byte[] bodyBytes = await e.GetResponseBody();
e.SetResponseBody(bodyBytes);
string body = await e.GetResponseBodyAsString();
e.SetResponseBodyString(body);
}
}
}
if (e.UserData != null)
{
// 從存儲(chǔ)在RequestHandler中的UserData屬性的訪問請求
var request = (Request)e.UserData;
}
}
// 允許重寫默認(rèn)的證書驗(yàn)證邏輯
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{
// 根據(jù)證書錯(cuò)誤,設(shè)置IsValid為真/假
if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
e.IsValid = true;
return Task.CompletedTask;
}
// 允許在相互身份驗(yàn)證期間重寫默認(rèn)客戶端證書選擇邏輯
public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{
// set e.clientCertificate to override
return Task.CompletedTask;
}
websocket處理
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);
//收到CONNECT請求時(shí)觸發(fā)
explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += ExplicitEndPoint_BeforeTunnelConnectResponse;
private async Task ExplicitEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
if (!barrageWsHostNames.Contains(hostname))
{
e.DecryptSsl = false;
}
}
private Task ExplicitEndPoint_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
if (!barrageWsHostNames.Contains(hostname))
{
e.DecryptSsl = false;
}
Console.WriteLine($"ExplicitEndPoint_BeforeTunnelConnectResponse url={hostname}");
if (e.UserData != null)
{
}
return Task.CompletedTask;
}
private async void WebSocket_DataReceived(object sender, DataEventArgs e)
{
var args = (SessionEventArgs)sender;
string hostname = args.HttpClient.Request.RequestUri.Host;
var processid = args.HttpClient.ProcessId.Value;
var frames = args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count).ToList();
foreach (var frame in frames)
{
base.SendWebSocketData(new WsMessageEventArgs()
{
ProcessID = processid,
HostName = hostname,
Payload = frame.Data.ToArray(),
ProcessName = base.GetProcessName(processid)
});
}
}
設(shè)為系統(tǒng)代理
//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);
// 只有顯式代理可以設(shè)置為系統(tǒng)代理!
proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
打開代理
Console.WriteLine("打開代理");
proxyServer.AddEndPoint(explicitEndPoint);
proxyServer.Start();
proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
關(guān)閉代理
Console.WriteLine("關(guān)閉代理");
proxyServer.ServerCertificateValidationCallback -= ProxyServer_ServerCertificateValidationCallback;
proxyServer.BeforeRequest -= ProxyServer_BeforeRequest;
proxyServer.BeforeResponse -= ProxyServer_BeforeResponse;
explicitEndPoint.BeforeTunnelConnectRequest -= ExplicitEndPoint_BeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse -= ExplicitEndPoint_BeforeTunnelConnectResponse;
proxyServer.Stop();
proxyServer.Dispose();
總結(jié)
TitaniumProxy 和 FiddlerCore 是兩個(gè)不同的 HTTP(S) 代理服務(wù)器,它們有以下一些區(qū)別:
- 設(shè)計(jì)和架構(gòu):TitaniumProxy 是一個(gè)重新實(shí)現(xiàn)的 FiddlerCore亏较,具有更合理的框架設(shè)計(jì)和易于擴(kuò)展的特點(diǎn)莺褒。FiddlerCore 可能在某些方面存在設(shè)計(jì)上的不足,如 API 命名不規(guī)范雪情、屬性/字段混用等遵岩。
- 性能和資源使用:TitaniumProxy 被宣傳為具有低內(nèi)存和高性能的特點(diǎn)。具體的性能差異可能因?qū)嶋H使用情況而異巡通,但在一些情況下尘执,TitaniumProxy 可能更適合對性能要求較高的場景。
- 功能和特性:兩者的功能可能會(huì)有所不同扁达。具體取決于它們的版本和配置正卧。一些可能的差異包括對協(xié)議的支持、代理規(guī)則的靈活性跪解、數(shù)據(jù)過濾和修改的能力等炉旷。
- 社區(qū)和支持:FiddlerCore 是由 Telerik 開發(fā)的,可能有更廣泛的社區(qū)和文檔支持叉讥。TitaniumProxy 可能是一個(gè)相對較新的項(xiàng)目窘行,社區(qū)和支持可能相對較小。
在選擇使用哪個(gè)代理服務(wù)器時(shí)图仓,你可以考慮以下因素:
- 具體需求:根據(jù)你的具體需求確定所需的功能和特性罐盔。
- 性能要求:如果對性能有較高要求,可以評估兩者在實(shí)際使用中的性能表現(xiàn)救崔。
- 開發(fā)和集成:考慮與你的開發(fā)環(huán)境和項(xiàng)目的集成難易程度惶看。
- 社區(qū)和支持:一個(gè)活躍的社區(qū)和良好的文檔支持可以幫助你解決問題和獲取更多資源。
記得無論用哪種方式創(chuàng)建代理六孵,程序結(jié)束時(shí)都要關(guān)閉代理纬黎,否則電腦為斷網(wǎng);解決斷網(wǎng)的方法就是重新開應(yīng)用,再正常關(guān)閉應(yīng)用即可劫窒。
下一篇將用兩個(gè)實(shí)際案例:美元匯率監(jiān)控和直播間彈幕抓取項(xiàng)目本今,結(jié)合FiddlerCore和TitaniumProxy寫代碼。