using System.Net; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Extensions.Caching.Memory; namespace MegghysAPI.Modules { /// /// 代理IP管理器 /// public static class ProxyManager { // 用于获取代理IP的客户端,不使用代理 private static readonly HttpClient ProxyApiHttpClient = new(); // 缓存代理IP的响应 private static readonly MemoryCache ProxyResponseCache = new(new MemoryCacheOptions()); // 缓存配置了代理的HttpClient private static readonly MemoryCache HttpClientCache = new(new MemoryCacheOptions()); private const string BaseUrl = "https://share.proxy.qg.net/get"; private const string DefaultKey = "9IK2T3XL"; private const string DefaultPassword = "04BC86C88CDB"; /// /// 获取配置了代理的 HttpClient,带缓存和自动释放功能 /// /// 可选的代理地址。如果为空,则自动获取。 /// 代理用户名 /// 代理密码 /// 配置好代理的 HttpClient public static async Task GetHttpClientAsync(string? proxyAddress = null, string key = DefaultKey, string password = DefaultPassword) { // 如果未提供代理地址,则从API获取 if (string.IsNullOrWhiteSpace(proxyAddress)) { var proxyResponse = await GetProxyAsync(key: key); var proxyIp = proxyResponse?.Data?.FirstOrDefault(); if (proxyIp?.Server == null || proxyIp.Deadline == null) { // 如果无法获取有效代理,返回一个不带代理的普通HttpClient return new HttpClient(); } // 检查缓存中是否已有此代理的HttpClient if (HttpClientCache.TryGetValue(proxyIp.Server, out HttpClient? cachedClient)) { return cachedClient!; } // 创建新的HttpClient并配置缓存 var client = CreateConfiguredHttpClient(proxyIp.Server, key, password); var deadline = DateTime.Parse(proxyIp.Deadline); var cacheEntryOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(deadline) .RegisterPostEvictionCallback((cacheKey, value, reason, state) => { (value as HttpClient)?.Dispose(); }); HttpClientCache.Set(proxyIp.Server, client, cacheEntryOptions); return client; } else { // 如果用户手动提供了代理地址,我们无法知道其过期时间,因此不进行缓存 return CreateConfiguredHttpClient(proxyAddress, key, password); } } private static HttpClient CreateConfiguredHttpClient(string proxyAddress, string key, string password) { var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All, Proxy = new WebProxy(proxyAddress, false) { Credentials = new NetworkCredential(key, password) }, UseProxy = true }; var client = new HttpClient(handler, disposeHandler: true); client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"); return client; } /// /// 异步获取代理IP, 带缓存功能 /// public static async Task GetProxyAsync(string key = DefaultKey, string? area = null, string? areaEx = null, int? isp = null, int? num = null, bool? distinct = null) { var queryParams = new Dictionary { { "key", key }, { "area", area }, { "area_ex", areaEx }, { "isp", isp?.ToString() }, { "num", num?.ToString() }, { "distinct", distinct?.ToString().ToLower() } }; var queryString = string.Join("&", queryParams .Where(kvp => !string.IsNullOrEmpty(kvp.Value)) .Select(kvp => $"{kvp.Key}={Uri.EscapeDataString(kvp.Value!)}")); var cacheKey = $"ProxyResponse_{queryString}"; if (ProxyResponseCache.TryGetValue(cacheKey, out ProxyResponse? cachedResponse)) { return cachedResponse; } var requestUrl = $"{BaseUrl}?{queryString}"; try { var response = await ProxyApiHttpClient.GetAsync(requestUrl); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); var proxyResponse = JsonSerializer.Deserialize(json); if (proxyResponse?.Code == "SUCCESS" && proxyResponse.Data?.Any() == true) { // 使用代理的过期时间作为缓存的过期时间 var deadline = DateTime.Parse(proxyResponse.Data.First().Deadline!); ProxyResponseCache.Set(cacheKey, proxyResponse, deadline); } return proxyResponse; } catch (HttpRequestException e) { Console.WriteLine($"请求代理IP时发生错误: {e.Message}"); return null; } } } /// /// 代理IP接口响应 /// public class ProxyResponse { [JsonPropertyName("code")] public string? Code { get; set; } [JsonPropertyName("data")] public List? Data { get; set; } [JsonPropertyName("request_id")] public string? RequestId { get; set; } } /// /// 代理IP信息 /// public class ProxyIp { [JsonPropertyName("proxy_ip")] public string? ProxyIpAddress { get; set; } [JsonPropertyName("server")] public string? Server { get; set; } [JsonPropertyName("area")] public string? Area { get; set; } [JsonPropertyName("isp")] public string? Isp { get; set; } [JsonPropertyName("deadline")] public string? Deadline { get; set; } } }