为啥使用 HttpClient 而不是 HttpWebRequest 进行同步请求
Posted
技术标签:
【中文标题】为啥使用 HttpClient 而不是 HttpWebRequest 进行同步请求【英文标题】:Why use HttpClient over HttpWebRequest for synchronous requests为什么使用 HttpClient 而不是 HttpWebRequest 进行同步请求 【发布时间】:2017-08-01 16:28:45 【问题描述】:在我的场景中,我必须将数据从一个 Web 应用程序发送到一个有效数据存储的 webapi。这些请求必须是同步的,如果出现问题,我绝对希望抛出Exception
,因为这意味着应用程序的关键部分不可用。
这是现有问题的衍生问题,但不是重复问题; Why use HttpClient for Synchronous Connection.
然而,包括在我上面看到的文章中,我一遍又一遍地看到使用HttpClient
的一致建议,即使在同步场景中也是如此。我看到的最好的理由是上面 SO 帖子中接受的答案,但它基本上归结为;
因为“闪亮”而使用它。
我不喜欢作为我的方案可接受的答案。我更愿意为手头的任务使用正确的对象,这似乎是较旧的HttpWebRequest
。甚至 Ben Watson 的优秀资源“编写高性能 .NET 代码”也陈述了以下内容;
另一个例子是
System.Net.HttpWebRequest
类,它将 如果它从服务器接收到非 200 响应,则抛出异常。 谢天谢地,这种奇怪的行为在System.Net.Http.HttpClient
.NET 4.5 中的类
但在我的场景中,我实际上确实想要这种行为。虽然HttpClient
有很多很好的用例,但谁能提供一个在我的场景中不使用HttpWebRequest
的充分理由?我是否使用了正确的对象?更重要的是,为什么?
【问题讨论】:
【参考方案1】:HttpClient
旨在提供对 http 协议的更多控制,而在 HttpWebRequest
或 WebClient
中做同样的事情并不是那么简单。除了异步,HttpClient
还有很多好处
HttpClient
的好处
HttpClient
的最大好处是插件架构,它可以让您轻松更改 HTTP 协议的底层行为。
HttpClient
是可扩展的,底层 HttpMessageHandler
允许您完全绕过底层 Microsoft 的 HttpClient 实现,您可以插入自己的实现。例如,在 ios 和 android 中,我们可以使用原生 Http 堆栈,而不是使用 .Net 的 HttpClient。
通过自定义HttpMessageHandler
可以轻松替换缓存、cookies
当我们想取消长时间运行的 Http 请求时,CancellationToken
支持非常好。
不光彩,但很重要,多线程,HttpClient
被优化以管理单个实例的多个请求。 CPU 时间得到了非常有效的利用,无需使用太多锁(同步操作依赖于锁,这对 CPU 来说是相当大的开销)。今天,我们生活在微服务的世界中。在具有许多要服务的客户端的服务器和移动操作系统中,CPU 时间成本很高。
缺点
唯一的缺点是async/await
,你不能简单地在同步代码中使用异步库而不使用任务运行器或死锁。尽管有许多库支持如何同步使用异步代码。
HttpClient
对桌面应用程序没有太大的好处,有大量的 CPU 时间作为备用。
【讨论】:
这个链接支持了在同步代码中不使用异步库的原因。blog.stephencleary.com/2012/07/dont-block-on-async-code.html【参考方案2】:HttpClient
的行为被认为是“更干净”的,因为来自服务器的不成功响应并不一定意味着出现问题。虽然您的情况并非如此,但想象一个进程想要检查资源是否不存在,并期望它通常不存在。使用HttpWebRequest
,正常的执行流程会引发异常,这有点粗鲁,可能会使事情复杂化,而HttpClient
不会。
对于您的具体情况,区别可能无关紧要。不过,您的程序中的其他情况可能更喜欢HttpClient
行为,并且最好在单个 HTTP 客户端上进行标准化,而不必同时兼顾两个。
【讨论】:
【参考方案3】:HttpClient 不是 WebClient/HttpWebRequest 的替代品。 HttpWebRequest 为您提供了更大的灵活性,但同时它使您的代码更加冗长。 HttpClient 提供了一个简单的接口。如果您真的想要附加功能,您可以使用 HttpWebRequest 而不是 HttpClient。
就非 200 响应代码异常而言,HttpClient 提供了一种模拟该行为的方法。你必须调用
response.EnsureSuccessStatusCode();
更多详情请访问Usage of EnsureSuccessStatusCode and handling of HttpRequestException it throws
【讨论】:
以上是关于为啥使用 HttpClient 而不是 HttpWebRequest 进行同步请求的主要内容,如果未能解决你的问题,请参考以下文章
为啥我应该使用 OkHttp 而不是 android httpClient 和 AsyncTask
从 httpwebrequest 切换到 httpclient,我不知道如何发送我的标头?
HttpClient AutomaticDecompression 与 gzip 一起使用,而不是放气
为啥HttpClient请求返回400,URL请求返回302正常