广告
返回顶部
首页 > 资讯 > 精选 >怎么在c#中设置HttpClient超时
  • 822
分享到

怎么在c#中设置HttpClient超时

2023-06-14 06:06:10 822人浏览 独家记忆
摘要

这篇文章将为大家详细讲解有关怎么在C#中设置HttpClient超时,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。问题如果你经常用HttpClient去调用Restfull接口或传送文件,你

这篇文章将为大家详细讲解有关怎么在C#中设置HttpClient超时,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

问题

如果你经常用HttpClient去调用Restfull接口或传送文件,你可能会对HttpClient这个类处理Request(请求)超时的方式感到恼火,因为存在这两个问题:

  • timeout(超时)只能在HttpClient的class级别处理。也就是说,一旦设置好了,所有httpClient下的请求都会应用同样的超时设置,这显然不灵活,如果能够为每个request请求分别指定一个超时时间,将非常方便。

  • 当请求超时时,抛出的异常很不好辨认。你认为请求超时时,httpclient会抛出TimeoutException?,不,其实它会抛出一个TaskCanceledException,而单看这个异常,你一时还无法分辨是取消导致的还是真正超时导致的。

幸运的是,得益于HttpClient的灵活设计,可以非常容易的弥补此缺陷。
因此,我们将针对这两个问题做出解决方案。让我们回顾一下我们想要的:

  • 可以为每个request请求单独设置超时时间

  • 当超时发生时,catch的异常是TimeoutException而不是TaskCanceledException。

为每个request设置超时值

怎样将超时时间值和Request请求关联起来呢?HttpRequestMessage这个类有个Properties的属性,它是一个字典(Dictionary)类型的属性,我们可以放入我们任何自定义需要的内容到这个属性中。我们将使用这个属性存储请求(request)的超时时间,为了便于实现此功能,我们给HttpRequestMessage创建一个扩展方法:

public static class HttpRequestExtensions{  private static string TimeoutPropertyKey = "RequestTimeout";  public static void SetTimeout(    this HttpRequestMessage request,    TimeSpan? timeout)  {    if (request == null)      throw new ArgumentNullException(nameof(request));    request.Properties[TimeoutPropertyKey] = timeout;  }  public static TimeSpan? GetTimeout(this HttpRequestMessage request)  {    if (request == null)      throw new ArgumentNullException(nameof(request));    if (request.Properties.TryGetValue(        TimeoutPropertyKey,        out var value)      && value is TimeSpan timeout)      return timeout;    return null;  }}

这是一段很普通的代码,timout参数是可null的TimeSpan值,我们现在可以给请求设置超时值,但是目前还没有实际使用到这段代码。

Http Handler

HttpClient使用 管道体系( pipeline architecture) 结构:每个请求都通过一系列类型为HttpMessageHandler的Handler处理,并且以相反顺序逐级返回响应。有了这种机制,我们可以非常方便的加入我们自己的Handler来具体处理超时问题。如果您想了解更多,本文将对此进行更详细的说明。

我们的自己的超时Handler将继承DelegatingHandler,DelegatingHandler是一种设计为链式调用其他Handler的类(简单提一下:DelegatingHandler内部有个InnerHandler成员变量,我们可以在调用innerHandler.SendAsync()前后对request、CancellationToken和response做相应处理)。要实现我们的Handler,我们重写SendAsync方法。最小的实现如下所示:

class TimeoutHandler : DelegatingHandler{  protected async override Task<HttpResponseMessage> SendAsync(    HttpRequestMessage request,    CancellationToken cancellationToken)  {    return await base.SendAsync(request, cancellationToken);  }}

上述代码并没有任何用处,因为只是将实际处理丢给了base.SendAsync,目前还没有对TimeoutHandler进行任何加工处理,我们将逐步对其加强扩充,以达到我们的目的。

给Request加上超时处理

首先,让我们给TimeoutHandler添加一个TimeSpan类型的DefaultTimeout属性,这个默认超时时间是给没有特意设置超时时间的请求使用的:

public TimeSpan DefaultTimeout { get; set; } = TimeSpan.FromSeconds(100);

就像HttpClient.Timeout一样,我们也设置默认超时时间为100秒。

为了实现我们的超时处理,我们需要从request中获取超时时间(如果request中没有设置,则应用DefaultTimeout的值)。接着,我们创建一个在指定时间(超时时间)后将会被取消的CancellationToken,并把这个CancellationToken传入到链的下一个Handler。这样之后,如果指定超时时间内没有获取到response响应,我们刚刚创建的CancellationToken就会被取消(cancel)。

我们创建一个CancellationTokenSource,这个类可以创建和控制CancellationToken。它将根据超时时间来创建:

private CancellationTokenSource GetCancellationTokenSource(  HttpRequestMessage request,  CancellationToken cancellationToken){  var timeout = request.GetTimeout() ?? DefaultTimeout;  if (timeout == Timeout.InfiniteTimeSpan)  {    // No need to create a CTS if there's no timeout    //不需要创建CTS,因为不处理超时(下面会讲到)    return null;  }  else  {    var cts = CancellationTokenSource      .CreateLinkedTokenSource(cancellationToken);    cts.CancelAfter(timeout);    return cts;  }}

这里主要关注两个点:

  • 如果request超时值为Timeout.InfiniteTimeSpan,程序并不会创建CancellationTokenSource,它将不会被取消,因此节省了无用的分配。也就是说在这种情况下,我们将不会处理超时。

  • 以上相反,我们创建了一个在指定timeout后被自动取消的CancellationTokenSource(因为调用了CancelAfter)。请注意,这个CTS连接了传入参数的cancellationToken,这个cancellationToken其实来自SendAsync方法的实参。这样做之后,当真正的超时发生,或者参数的cancellationToken自身被取消,CTS都会被取消。如果想要获取跟多CancellationToken的内容,请访问这篇文章

最后,我们修改下SendAsync方法,应用刚刚创建的CancellationTokenSource。

protected async override Task<HttpResponseMessage> SendAsync(  HttpRequestMessage request,  CancellationToken cancellationToken){  using (var cts = GetCancellationTokenSource(request, cancellationToken))  {    return await base.SendAsync(      request,      cts?.Token ?? cancellationToken);  }}

我们创建了CTS后,把CTS的token传入到base.SendAsync中,注意,我们使用cts?.Token是因为GetCancellationTokenSource返回的cts可能为null,如果cts为null,则直接使用参数自己的cancellationToken,我们就不做任何超时处理。

通过这一步,我们有了自己的超时Handler,可以为每个请求指定不同的超时时间。但是,当超时发生时,我们仍然只能捕获到TaskCanceledException异常,这个问题很容易修复它。

抛出正确的异常

我们需要捕获TaskCanceledException(或者它的基类OperationCanceledException),然后检测cancellationToken参数是否是被取消的:

  • 如果是,说明这个cancel是调用者自身导致的,对此直接将异常上抛不处理

  • 如果不是,这意味着是因为我们的超时导致的cancel,因此,我们将抛出一个TimeoutException

这是最终的SendAsync方法:

protected async override Task<HttpResponseMessage> SendAsync(  HttpRequestMessage request,  CancellationToken cancellationToken){  using (var cts = GetCancellationTokenSource(request, cancellationToken))  {    try    {      return await base.SendAsync(        request,        cts?.Token ?? cancellationToken);    }    catch(OperationCanceledException)      when (!cancellationToken.IsCancellationRequested)    {      throw new TimeoutException();    }  }}

我们使用了一个exception filter,通过这种方式,我们只cactch我们符合我们情况需要的异常,然后做相应处理。

至此,我们的超时Handler已经完成了,接下来看看怎么使用它

使用Handler

当创建一个HttpClient时,可以指定一个自己的Handler作为管道(pipeline)的第一个Handler。如果没有指定,默认使用的是HttpClientHandler,这个handler直接发送请求到网络上。为了使用我们自己的TimeoutHandler,我们需要先创建它,然后将timeoutHandler指定为httpClient的handler。在timeoutHandler中,指定InnerHandler为我们自己创建的HttpClientHandler,这样实际的网络请求就委托到了HttpClientHandler中。

var handler = new TimeoutHandler{  InnerHandler = new HttpClientHandler()};using (var client = new HttpClient(handler)){  client.Timeout = Timeout.InfiniteTimeSpan;  ...}

通过将httpclient的timeout设置为InfiniteTimeSpan来禁用默认的超时设置,如果不这样做,默认超时会干扰我们自己的超时

现在,我们尝试发送一个设定了5秒超时的请求到需要很久才能响应的服务器

var request = new HttpRequestMessage(HttpMethod.Get, "http://foo/");request.SetTimeout(TimeSpan.FromSeconds(5));var response = await client.SendAsync(request);

如果服务器在5秒内响应数据,我们将会捕获到一个TimeoutException,而不是TaskCanceledException,因此事情似乎按预期进行。

为了检测cancellation是否正确运行,我们传入一个在2秒(比超时实际小)后会被取消的CancellationToken:

var request = new HttpRequestMessage(HttpMethod.Get, "http://foo/");request.SetTimeout(TimeSpan.FromSeconds(5));var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));var response = await client.SendAsync(request, cts.Token);

这时,我们可以捕获到TaskCanceledException,这正是我们期望的。

关于怎么在c#中设置HttpClient超时就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 怎么在c#中设置HttpClient超时

本文链接: https://www.lsjlt.com/news/268451.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 怎么在c#中设置HttpClient超时
    这篇文章将为大家详细讲解有关怎么在c#中设置HttpClient超时,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。问题如果你经常用HttpClient去调用Restfull接口或传送文件,你...
    99+
    2023-06-14
  • c# HttpClient设置超时的步骤
    目录问题 为每个request设置超时值 Http Handler 给Request加上超时处理 抛出正确的异常 使用Handler 总结 HttpClient作为官方推荐的http...
    99+
    2022-11-11
  • 怎么在golang中使用GRPC设置client超时时间
    这篇文章给大家介绍怎么在golang中使用GRPC设置client超时时间,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。什么是golanggolang 是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收...
    99+
    2023-06-14
  • php.ini怎么设置超时时间
    本教程操作环境:windows7系统、PHP7.1版,DELL G3电脑php.ini 中缺省的最长执行时间是 30 秒,这是由 php.ini 中的 max_execution_time 变量指定,倘若你有一个需要颇多时间才能完成的工作,...
    99+
    2021-08-07
    php.ini 超时时间
  • MySQL中怎么设置查询超时
    本篇文章为大家展示了MySQL中怎么设置查询超时,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。为了优化OceanBase的query timeout设置方式,特调研...
    99+
    2022-10-18
  • redis怎么设置hash超时时间
    Redis中的hash类型是没有超时时间的,但是可以通过设置hash中每个field的值为一个带有超时时间的字符串或者其他数据类型来...
    99+
    2023-09-01
    redis
  • golang在GRPC中设置client的超时时间
    超时 建立连接 主要就2函数Dail和DialContext。 // Dial creates a client connection to the given target. ...
    99+
    2022-11-12
  • mysql 中怎么设置事务锁超时时间
    mysql 中怎么设置事务锁超时时间,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Mysql数据库采用InnoDB模式,默认参数:innodb...
    99+
    2022-10-18
  • weblogic事务超时怎么设置
    在WebLogic中,您可以通过以下步骤来设置事务超时时间: 打开WebLogic管理控制台。 导航到您的WebLogic域。 在...
    99+
    2023-10-27
    weblogic
  • 怎么设置session永不超时
    要设置Session永不超时,可以通过以下几种方法:1. 在服务器端设置Session超时时间为较大的值或者设置为0,表示永不超时。...
    99+
    2023-08-18
    session
  • mysql事务超时时间怎么设置
    在MySQL中,事务超时时间是由两个参数控制的:innodb_lock_wait_timeout和innodb_rollback_o...
    99+
    2023-10-26
    mysql
  • mysql怎么设置session的超时时间
    本篇内容介绍了“mysql怎么设置session的超时时间”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2022-10-18
  • PHP连接超时时间怎么设置
    在我们使用PHP进行网络请求时,有时候我们需要调整连接超时时间来适应不同的网络环境和请求类型。本文将介绍PHP连接超时时间,其原理和设置方法。连接超时时间是指当我们进行网络请求时,如果服务器无法响应请求,那么客户端需要等待多长时间后才会超时...
    99+
    2023-05-14
    php
  • php怎么设置超时等待时间
    在使用 PHP 进行开发时,有时需要执行耗时较长的操作,例如网络请求、数据库查询、文件操作等。在这种情况下,PHP 默认的超时时间可能不足以完成这些操作,导致程序出错。为了解决这个问题,我们需要设置 PHP 的超时等待时间。PHP 的超时等...
    99+
    2023-05-14
  • php怎么设置会话超时时间
    PHP以其易学易用和功能强大的特点,成为了Web开发的标准语言之一。然而,在Web应用程序中,会话超时的问题困扰着很多开发者。会话超时是指当用户一段时间内没有任何操作时,服务端会话会自动过期,会话数据会被清空。在某些情况下,我们希望控制会话...
    99+
    2023-05-14
  • jdbc怎么设置连接超时时间
    在JDBC中,可以使用`java.sql.Statement`或`java.sql.Connection`对象的`setQueryT...
    99+
    2023-10-27
    jdbc
  • php怎么设置最大超时时间
    在PHP中,可以通过设置php.ini文件中的max_execution_time参数来设置最大超时时间。步骤如下:1. 打开php...
    99+
    2023-08-24
    php
  • C# 中怎么设置Excel表格超链接
    本篇文章为大家展示了C# 中怎么设置Excel表格超链接,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。需要使用的工具:Free Spire.XLS for .NET 8.3 (社区版)Visual ...
    99+
    2023-06-03
  • 服务器session超时时间怎么设置
    服务器session超时时间可以通过修改web服务器的配置文件来设置。具体操作步骤如下:1. 打开web服务器的配置文件,如Apac...
    99+
    2023-06-10
    session超时 session
  • php 脚本怎么设置不超时
    本文操作环境:windows7系统、PHP7.1版,DELL G3电脑php 脚本怎么设置不超时?PHP脚本执行超时的解决办法PHP设置脚本最大执行时间的三种方法在php.ini里面设置max_execution_time = 120;通过...
    99+
    2017-12-05
    php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作