2015-05-27 73 views
4

最近我在.Net 4.5.1上使用HttpClients.PostAsync时遇到了性能问题。最初服务器(Owin + WebApi)在发送之前缓冲响应。这导致了巨大的内存使用开销(串行响应大小> 1Gb)。打开服务器客户端上的响应流后,字面上停止工作。事实证明,原因是当从服务器读取响应时,客户端上的缓冲区重新分配。我查了一下HttpClient的执行情况和HttpClient.SendAsync方法发现了这个有趣的部分:为什么HttpClient.PostAsync缓冲区响应?

if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead) 
{ 
    this.SetTaskCompleted(request, linkedCts, tcs, result); 
} 
else 
{ 
    this.StartContentBuffering(request, linkedCts, tcs, result); 
} 

所以当completionOption不是ResponseHeadersRead响应总是缓冲。根据SendAsync documentation执行SendAsync是否符合意图。

现在,由于PostAsync实现了发送ResponseContentRead,响应流总是在POST上缓冲。所以问题是为什么PostAsync必须等待(并缓冲)整个响应才能在处理继续之前到达?

回答

7

有一个显而易见的部分 - 如果您没有指定HttpCompletionOption.ResponseHeadersReadTask将只在读取整个响应时才会完成;在此期间您必须将响应数据存储在某处

为什么PostAsync不允许您指定HttpCompletionOption.ResponseHeadersRead?可能是因为它在大多数情况下都不是很有用。 POST用于发布数据,而不是用于检索数据 - 这是GET的工作。 HttpClient是围绕WebAPI和“REST”服务设计的,适当使用HTTP动词。

如果您需要使用POST来获取如此大量的数据,你有两个基本的选择:

  • 使用SendAsync
  • 不要使用HttpClientHttpWebRequest是有点复杂,但给人你的方式更多控制)
+0

我必须使用POST,因为我的请求对象'不适合'GET方法。无论如何,我改变了实现,以显式调用SendAsync – koruyucu

+0

@ koruyucu是的,这可能会很棘手。完全解决这个REST的通常方法是使用例如'PUT'将您的请求对象推送到服务器,它将返回一个URL到'GET'来检索响应。但它可能会产生比解决问题更多的麻烦:D – Luaan

+1

@Luaan,因为它可以解决* nothing *,清楚:) – usr