HttpClient与HttpWebRequest的区别

47

我有一个大文件需要发送给 Web API 客户端...数据是多部分的。 问题在于,如果使用 HTTP Web 请求发送文件,则它会快速上传到 Web API。对于此请求,文件内容直接写入请求流中。

相反,如果使用 HttpClient(.NET 4.5)发送相同的文件,则上传速度比 HTTP Web 请求慢。我在 Httpclient post async 中使用了 multipartformdatacontent。

那么,对于大文件,我们只能使用 Web 请求吗?或者 HttpClient 中是否有任何设置可以使上传更快?


1
HttpWebRequest 模型单独代表一个请求。HttpClient 则代表客户端,可以进行多个请求。HttpClient 更加现代化,因此更有可能拥有最新的知识。尽管我不知道它在某些方面是否特别快,但如果你要做任何与 WebAPI 或 REST 相关的事情,HttpClient 肯定更值得推荐。 - Peter Ritchie
4
HttpClient在底层使用HttpWebRequest来实际发起HTTP请求,因此您应该能够获得相同的性能。 - Darrel Miller
1
是的,但性能取决于内容如何通过客户端传递。我使用了FileStreamContent,现在我已经改为ByteArrayContent... - user2325247
HttpWebRequest已过时,案件结案: SYSLIB9914:'WebRequest.Create(string)'已过时:'WebRequest,HttpWebRequest,ServicePoint和WebClient已弃用。请改用HttpClient。' - NetXpert
3个回答

51

HttpClient更像是一个无界面浏览器。如果你需要创建多个http请求,它是一个强大而理想的工具,例如你可以设置默认头和其他内容。以下是与HttpWebRequest的五个不同之处,摘自这里

  1. HttpClient实例是配置扩展、设置默认头、取消未完成的请求等操作的场所。
  2. 你可以通过单个HttpClient实例发出任意多次请求。
  3. HttpClient并不绑定于特定的HTTP服务器或主机;你可以使用同一HttpClient实例提交任何HTTP请求。
  4. 你可以派生HttpClient来创建专门针对特定站点或模式的客户端。
  5. HttpClient使用新的任务导向模式处理异步请求,因此管理和协调多个未完成的请求变得极其容易。

6
谢谢。这并没有回答我的问题。我使用了postAsync方法的await,但它仍然没有帮助。我想知道相比于HttpClient,WebRequest为什么更快? - user2325247
3
通常建议进行归属:http://blogs.msdn.com/b/henrikn/archive/2012/02/11/httpclient-is-here.aspx - Paddy
3
在帖子中两次提及归属,再加上评论区的一次,这真的很有趣... :-) - Giuseppe
1
很棒的答案。仅前7个单词就可以解决许多“为什么我无法使用HttpClient爬取xyz.com?”的问题。 - pim
链接中使用了JsonArray资源,但似乎该资源不可用。 - KansaiRobot

5

我之前使用了FileStreamContent来和httpclient交互...但当我改用ByteArrayContent时,它正常工作了。

我不确定为什么这样做有所不同,但是通过流发送字节比发送流更好。


你从哪里获取到 FileStreamContent 的?它不是一个默认的 HttpContent 实现。 - Darrel Miller
不是的。我很确定它不在这两个之间。 - Darrel Miller
1
我的错误..我是在谈论StreamContent。http://msdn.microsoft.com/zh-cn/library/system.net.http.streamcontent(v=vs.110).aspx - user2325247
在问题和答案中展示代码片段会很有帮助。我猜测你的字节数组比默认的流缓冲区大得多,这有助于httpclient以更少的开销发送它。 - ToolmakerSteve

5

如果你在using块中实例化了HttpClient,这可能会导致性能问题。例如:

  using (var httpClient = new HttpClient() )
  {
      var result = await httpClient.GetAsync("http://example.com");
      Console.WriteLine(result.StatusCode);
  }

在此代码中,HttpClient实例立即被处理,然而它应该是一个长期存在的对象(例如,与应用程序的生命周期相同)。

[编辑 - 添加背景]

处理实例也会关闭连接,但会将套接字保持在等待状态一段时间。每执行一次此代码,操作系统都会尝试创建新的套接字连接,由于完成这个过程的速度存在限制,因此可能会出现性能/可靠性问题。

重用同一个HttpClient实例意味着更好地重复使用开放的套接字,并更有效地使用系统资源。

更多信息请点击此处


CS4033:“'await'运算符只能在异步方法中使用。请考虑使用'async'修饰符标记此方法,并将其返回类型更改为'Task'。”那么,围绕此代码的方法声明是什么样子的?在相应的返回语句中,有效的Task<T>值是什么? - NetXpert
@NetXpert 我认为你没有理解重点。这个代码块只是为了说明如何在using块中实例化httpclient而被误用。将其包装在方法定义中并没有增加任何价值。此外,OP指定了 .Net 4.5 作为目标。 - mounds
此外,OP指定了.Net 4.5作为目标 - 这就是为什么我特别添加了注释“这不是当代有效的代码示例”的原因 - 这样,这篇文章的未来读者会看到一个注释,指出它不再是有效的C#代码。 - NetXpert
@NetXpert 代码示例编译和运行正常。
  1. 创建一个C#控制台程序,目标为.net framework 4.5。
  2. 从Nuget导入System.Net.Http。
  3. 添加一个异步方法(例如public static Task DoStuff),并将我的代码粘贴到其主体中,将“example.com”更改为您想要垃圾邮件的网址,并从您的主方法中调用它*。
  4. 构建并运行它。
在GetAsync被'await'后,StatusCode确实是System.Net.Http.HttpResponseMessage的属性。
  • 如果您需要帮助创建/调用异步方法,请在SO上提问,我相信有人会愿意帮助您。
- mounds
如果以上代码“编译并正常运行”,那么我为什么需要你的第三步呢? 请记住,我特别问过你包装方法的外观和应该应用的有效返回类型,而你说我错过了重点……当你说“上面的代码没问题”然后又添加“……如果你首先做这些其他事情(这正是你所询问的内容)”时,你就无法被认真对待,同时还试图声称我错过了重点。 - NetXpert
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接