以前是写前端的,感觉前端的类似axios的拦截器很方便,可以在请求的发送前后做一些通用化的操作,现在以为工作原因刚刚接触.NET,在.NET中请求库中经过挑选最后选择了HTTPClient这个类库,就在想有没有类似axios拦截库一样的功能,在查了一下官网文档,是推荐在应用程序的入口处就using,这样在整个应用周期中都可以使用HTTPClient。
先贴一下应用入口的代码:
/** * 使用HttpClinet实例 */ public static readonly HttpClient httpClient = new HttpClient();
以上代码是最简单的引入HTTPClient请求库,现在贴一下简单版本的DelegatingHandler拦截器代码:
public class CustomDelegatingHandler : DelegatingHandler { private readonly TimeSpan _timeout; public CustomDelegatingHandler(TimeSpan timeout) { _timeout = timeout; } // 请求前拦截 protected async Task<HttpRequestMessage> InterceptRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Console.WriteLine($"Sending request to {request.RequestUri}"); return request; } // 响应后拦截 protected async Task<HttpResponseMessage> InterceptResponseAsync(HttpResponseMessage response, CancellationToken cancellationToken) { Console.WriteLine($"Received response with status code {response.StatusCode}"); if (response.StatusCode == System.Net.HttpStatusCode.OK) { return response; } else if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) { Console.WriteLine("响应返回了状态码 500 - Internal Server Error"); MessageBox.Show("未接收到正确返回信息。", "提示信息", MessageBoxButton.OK, MessageBoxImage.Information); } else { Console.WriteLine($"响应返回了其他状态码: {(int)response.StatusCode}"); MessageBox.Show($"接收到错误返回信息{(int)response.StatusCode},请联系信息科。", "提示信息", MessageBoxButton.OK, MessageBoxImage.Information); } return response; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // 请求前拦截 var interceptedRequest = await InterceptRequestAsync(request, cancellationToken); // 创建一个链接到原始cancellationToken的新CancellationTokenSource using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { // 设置超时时间(例如30秒) linkedCts.CancelAfter(TimeSpan.FromSeconds(30)); HttpResponseMessage response = null; try { // 使用linkedCts.Token而不是原始的cancellationToken response = await base.SendAsync(interceptedRequest, linkedCts.Token); response.EnsureSuccessStatusCode(); } catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) { // 如果超时发生 throw new TimeoutException("The request timed out."); } catch (Exception) { throw; // 其他异常保持原样抛出 } // 响应后拦截 return await InterceptResponseAsync(response, linkedCts.Token); } } }
然后再在将应用入口的引入代码更改为:
public static readonly HttpClient httpClient = new HttpClient(new CustomDelegatingHandler(TimeSpan.FromSeconds(10)));
这里有一个非常重要的踩坑点需要注意,在实际运用程序的时候,会在response = await base.SendAsync(interceptedRequest, linkedCts.Token);卡住没有反应,需要将入口处的引入修改成如下所示就能解决。
public static readonly HttpClient httpClient = new HttpClient(new CustomDelegatingHandler(TimeSpan.FromSeconds(10)) { InnerHandler = new HttpClientHandler() });
关于为什么会卡住,猜测是因为