手動在 IE 設定代理、刷新 whatismyip.com 驗證極其低效。程式化驗證核心邏輯:
WebProxy 物件;HttpWebRequest.Proxy = proxy;https://httpbin.org/ip、https://api.ipify.org);origin 或 ip 欄位,若與代理 IP 一致則判定可用;Via、X-Forwarded-For 標頭)。
public class ProxyValidator {
private static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
public static async Task CheckAsync(string ip, int port, string testUrl = "https://httpbin.org/ip") {
var proxy = new WebProxy(ip, port);
using var handler = new HttpClientHandler { Proxy = proxy, UseProxy = true };
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(10) };
var sw = Stopwatch.StartNew();
try {
string json = await client.GetStringAsync(testUrl);
sw.Stop();
// 解析 JSON: {"origin": "x.x.x.x"}
using var doc = JsonDocument.Parse(json);
string origin = doc.RootElement.GetProperty("origin").GetString();
bool success = origin?.Contains(ip) == true;
return new ProxyCheckResult {
Ip = ip, Port = port, Success = success, LatencyMs = (int)sw.ElapsedMilliseconds,
ResponseIp = origin, CheckTime = DateTime.Now
};
}
catch (Exception ex) {
sw.Stop();
return new ProxyCheckResult {
Ip = ip, Port = port, Success = false, LatencyMs = (int)sw.ElapsedMilliseconds,
Error = ex.Message, CheckTime = DateTime.Now
};
}
}
}
public class ProxyCheckResult {
public string Ip { get; set; }
public int Port { get; set; }
public bool Success { get; set; }
public int LatencyMs { get; set; }
public string ResponseIp { get; set; }
public string Error { get; set; }
public DateTime CheckTime { get; set; }
}
public class BulkProxyValidator {
private readonly SemaphoreSlim _semaphore;
private readonly HttpClient _client;
public BulkProxyValidator(int maxConcurrency = 50) {
_semaphore = new SemaphoreSlim(maxConcurrency);
_client = new HttpClient(new HttpClientHandler { UseProxy = true }) { Timeout = TimeSpan.FromSeconds(8) };
}
public async Task> ValidateAsync(IEnumerable<(string ip, int port)> proxies, string testUrl = "https://httpbin.org/ip") {
var tasks = proxies.Select(async p => {
await _semaphore.WaitAsync();
try {
return await CheckSingleAsync(p.ip, p.port, testUrl);
}
finally { _semaphore.Release(); }
});
return (await Task.WhenAll(tasks)).Where(r => r.Success).OrderBy(r => r.LatencyMs).ToList();
}
private async Task CheckSingleAsync(string ip, int port, string testUrl) {
var proxy = new WebProxy(ip, port);
var handler = new HttpClientHandler { Proxy = proxy, UseProxy = true };
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(8) };
var sw = Stopwatch.StartNew();
try {
string json = await client.GetStringAsync(testUrl);
sw.Stop();
using var doc = JsonDocument.Parse(json);
string origin = doc.RootElement.GetProperty("origin").GetString();
return new ProxyCheckResult {
Ip = ip, Port = port, Success = origin?.Contains(ip) == true,
LatencyMs = (int)sw.ElapsedMilliseconds, ResponseIp = origin
};
}
catch (Exception ex) {
sw.Stop();
return new ProxyCheckResult { Ip = ip, Port = port, Success = false, LatencyMs = (int)sw.ElapsedMilliseconds, Error = ex.Message };
}
}
}
| 指標 | 檢測方法 | 意義 |
|---|---|---|
| 匿名度 | 請求 https://httpbin.org/headers,檢查 Via、X-Forwarded-For、X-Real-IP 標頭是否包含真實 IP | 高匿無標頭、普匿有標頭但無真實 IP、透明攜帶真實 IP |
| 協議支援 | 分別測 HTTP/HTTPS 目標站點 | 確認代理是否支援 CONNECT 隧道 |
| 目標站點可達性 | 針對業務目標域名(如 www.google.com)測試 | 避免代理能訪問驗證站但不能訪問業務站 |
| 穩定性 | 連續 3 次成功才判定可用,失敗 1 次即標記不穩定 | 減少波動代理污染池 |
HttpClient + HttpClientHandler,支援異步、連接池、自動解壓、現代 TLS。 SemaphoreSlim 限制併發數,避免大量併發導致本機端口耗盡或觸發目標站防火牆。 httpbin.org/ip、api.ipify.org?format=json、ipinfo.io/json,回應結構穩定易解析。 ProxyCheckResult,便於持久化、排序、UI 綁定。 TaskCanceledException、HttpRequestException、SocketException,記錄錯誤碼便於分析。 BackgroundService (Generic Host) 定時掃描代理池;ZADD proxy:valid {score} {ip:port}),Score 為延遲,業務端 ZRANGE proxy:valid 0 9 取最快 10 個;proxy:invalid,每日重試一次;代理驗證看似簡單,生產環境關鍵在於 異步並發控制、標準化驗證端點、多維度指標(匿名度/協議/目標站可達性)、結果持久化與服務化。本文提供從單驗證到批量服務的完整演進代碼,可直接集成至爬蟲框架、代理池服務或隱私工具中。