如何修复C#中PostAsync请求未生效的代理配置问题?
问题描述
基于.NET Framework 4.6.1开发WPF的.dll组件,服务通过HTTP请求访问Azure Function服务器。已实现修改用户设置及配置代理的界面,但请求并未应用配置好的代理设置。
静态类ConnexionService代码
public static class ConnexionService { private static HttpClient httpClient; private static HttpClientHandler clientHandler = new HttpClientHandler(); public static void SetupProxy() { try { if (Properties.Settings.Default.ProxyUsage) { // 代理服务器地址和端口 Uri proxyAddress = new Uri($"http://{Properties.Settings.Default.ProxyAdress}:{Properties.Settings.Default.ProxyPort}"); // 创建代理对象 WebProxy proxy = new WebProxy(Address: proxyAddress, BypassOnLocal: false) { UseDefaultCredentials = false, Credentials = new NetworkCredential( userName: Properties.Settings.Default.ProxyUser, password: Properties.Settings.Default.ProxyPassword) }; // 创建HttpClientHandler并配置代理 clientHandler = new HttpClientHandler() { UseProxy = true, Proxy = proxy }; httpClient = new HttpClient(handler: clientHandler, disposeHandler: true); } else { httpClient = new HttpClient(); } } catch(Exception e) { Console.WriteLine(e.ToString()); } } public static HttpClient getHttpClient() { SetupProxy(); return httpClient; } }
AuthenticationService中的使用代码
public class AuthenticationService { private readonly string Path = $"{Properties.Settings.Default.URL_API_DEV}/authentication"; public async Task<Profile> LogIn(Profile profile) { var encryption = new Encryption(); HttpContent content = new StringContent(encryption.Encrypt(JsonConvert.SerializeObject(profile)), Encoding.UTF8, "text/plain"); try { using (var client = ConnexionService.getHttpClient()) { var endpoint = new Uri($"{Path.Trim()}/login"); var send = await client.PostAsync(endpoint, content); if (!send.IsSuccessStatusCode) { Console.WriteLine($"错误 : {send.StatusCode}"); return new Profile(); } var encryptedResult = await send.Content.ReadAsStringAsync(); var decryptedResult = encryption.Decrypt(encryptedResult); var response = JsonConvert.DeserializeObject<Profile>(decryptedResult); return response; } } catch (HttpRequestException e) { Console.WriteLine($"错误 : {e.Message}"); return new Profile(); } } }
问题分析与修复方案
核心问题
- 错误使用
using销毁静态HttpClient:AuthenticationService中用using (var client = ConnexionService.getHttpClient())会自动销毁静态的httpClient实例,导致后续请求时实例已失效,代理配置无法生效,还会引发套接字资源耗尽问题。 - 重复创建HttpClient:
getHttpClient()每次调用都会执行SetupProxy()重新创建HttpClient,违背了HttpClient设计为复用的原则,也会导致代理配置无法稳定生效。
修复步骤
移除
using语句:静态HttpClient为长期复用设计,无需每次请求销毁,直接复用即可:// 替换原using块代码 var client = ConnexionService.getHttpClient(); var endpoint = new Uri($"{Path.Trim()}/login"); var send = await client.PostAsync(endpoint, content); // 后续逻辑保持不变优化ConnexionService逻辑:仅在代理配置变化时更新HttpClient实例,避免重复创建:
public static class ConnexionService { private static HttpClient httpClient; private static HttpClientHandler clientHandler; // 记录当前代理配置,判断是否需要更新 private static bool _currentProxyUsage; private static string _currentProxyAddress; private static int _currentProxyPort; private static string _currentProxyUser; public static void SetupProxy() { try { var settings = Properties.Settings.Default; // 配置无变化则直接返回 if (httpClient != null && _currentProxyUsage == settings.ProxyUsage && _currentProxyAddress == settings.ProxyAdress && _currentProxyPort == settings.ProxyPort && _currentProxyUser == settings.ProxyUser) { return; } // 销毁旧实例 httpClient?.Dispose(); clientHandler?.Dispose(); if (settings.ProxyUsage) { Uri proxyAddress = new Uri($"http://{settings.ProxyAdress}:{settings.ProxyPort}"); WebProxy proxy = new WebProxy(proxyAddress, BypassOnLocal: false) { UseDefaultCredentials = false, Credentials = new NetworkCredential(settings.ProxyUser, settings.ProxyPassword) }; clientHandler = new HttpClientHandler() { UseProxy = true, Proxy = proxy }; httpClient = new HttpClient(clientHandler, disposeHandler: true); // 更新配置记录 _currentProxyUsage = true; _currentProxyAddress = settings.ProxyAdress; _currentProxyPort = settings.ProxyPort; _currentProxyUser = settings.ProxyUser; } else { httpClient = new HttpClient(); // 更新配置记录 _currentProxyUsage = false; _currentProxyAddress = null; _currentProxyPort = 0; _currentProxyUser = null; } } catch(Exception e) { Console.WriteLine(e.ToString()); } } public static HttpClient getHttpClient() { SetupProxy(); return httpClient; } }监听配置变化:用户修改代理设置后,主动调用
ConnexionService.SetupProxy()触发实例更新,确保新配置立即生效。
内容的提问来源于stack exchange,提问作者Pablo Arrieumerlou
相关产品推荐
相关产品推荐

