【问题标题】:HttpClient and PushStreamContentHttpClient 和 PushStreamContent
【发布时间】:2014-08-21 15:02:24
【问题描述】:

我将 PushStreamContent 与我的 REST API (ASP.NET Web API) 一起使用,效果很好。 HttpClient 可以在服务器处理完整请求之前请求资源并获取 HTTP-Response(服务器仍然写入推送流)。

作为 HttpClient 你必须做一件小事:使用 HttpCompletionOption.ResponseHeadersRead。

现在我的问题是: 是否有可能以另一种方式做到这一点? 从 HttpClient -> 通过 push-stream 将数据上传到 web api?

我实现如下,但是 web api 没有在客户端关闭流之前获取请求。

         var asyncStream = new AsyncStream(fs);
         PushStreamContent streamContent = new PushStreamContent(asyncStream.WriteToStream);
         content.Add(streamContent);

         HttpResponseMessage response = await c.SendAsync(new HttpRequestMessage(new HttpMethod("POST"), "http://localhost/...") { Content = content }, HttpCompletionOption.ResponseHeadersRead);

         response.EnsureSuccessStatusCode();

AsyncStream 是我的委托类:

public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)

这是 Push-Stream 所必需的。

这有可能吗? HttpClient 不会将请求发送到 web api,直到最后一个字节被写入流......

我该怎么办?是客户端的问题还是服务器/asp.net web api端的问题?

编辑: 这是 WriteToStream 的实现(但我不使用磁盘中的文件,而是使用内存流“myMemoryStream”(在构造函数中传递):

public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
    try
    {
        var buffer = new byte[4096];

        using (var stream = myMemoryStream)
        {
            var bytesRead = 1;

            while (bytesRead > 0)
            {
                bytesRead = video.Read(buffer, 0, buffer.Length);
                outputStream.Write(buffer, 0, bytesRead);
            }
        }
    }
    catch (HttpException ex)
    {
        return;
    }
    finally
    {
        outputStream.Close();
    }
}

也许我需要处理:HttpContent 内容、TransportContext 上下文?

【问题讨论】:

    标签: c# asp.net-web-api httpclient pushstreamcontent


    【解决方案1】:

    我找到了解决问题的方法:

    我要设置:httpWebRequest.AllowReadStreamBuffering = false;

    HttpClient 4.0默认做缓冲,不能访问属性AllowReadStreamBuffering,所以必须直接使用HttpWebRequest。 (或者你可以使用HttpClinet 4.5,有默认行为'streaming')见:http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ 6. 使用HttpClient)

    第二个问题是 fiddler:Fiddler 目前只支持响应流,不支持请求 (Fiddler makes HttpWebRequest/HttpClient behaviour unexpected)

    对我有用的解决方案:

    HttpWebRequest httpWebRequest = HttpWebRequest.Create(...)
    httpWebRequest.Method = "POST";
             httpWebRequest.Headers["Authorization"] = "Basic " + ...;
             httpWebRequest.PreAuthenticate = true;
             httpWebRequest.AllowWriteStreamBuffering = false;
             httpWebRequest.AllowReadStreamBuffering = false;
             httpWebRequest.ContentType = "application/octet-stream";
             Stream st = httpWebRequest.GetRequestStream();
    st.Write(b, 0, b.Length);
    st.Write(b, 0, b.Length);
    //...
             Task<WebResponse> response = httpWebRequest.GetResponseAsync();
    
             var x = response.Result;
             Stream resultStream = x.GetResponseStream();
    //... read result-stream ...
    

    【讨论】:

    • 示例见这里。我的另一个答案是一些代码:stackoverflow.com/questions/25551887/…
    • 这仅适用于理想情况,不幸的是这不是一个可行的选择。客户端足够顽固地继续写入其整个流,即使服务器长时间出错并返回 HTTP 状态也是如此。客户端不会读取服务器发送的任何内容,除非它完成了它的请求,令人惊讶的是,即使在关闭应用程序池、IIS 并且底层套接字也关闭之后也是如此。我已经尝试将 HttpWebRequest 降低一级以尝试在客户端仍在写入时读取流,但是不允许此操作。
    【解决方案2】:

    确保在您的请求消息上使用requestMessage.Headers.TransferEncodingChunked = true;...原因是如果您不设置此选项,HttpClient 将在客户端本身缓冲整个内容,以便确定请求的 Content-length 和这就是您注意到在写入流时没有立即调用 Web api 服务的原因...

    【讨论】:

    • 嗨,谢谢,这是一个很好的信息。不幸的是,它不起作用。客户端仍然等待流的 close() ,然后才发送请求。另一种方式:如果服务器将第一个字节写入流,我会在客户端得到反应。但是,如果客户端写入第一个字节,则什么也不会发生。它写入末尾并关闭流。然后发送请求。奇怪的是,如果服务器在流中读取,他会得到 0 个字节......(只有当我在客户端-httprequestmessage 上激活分块时才会发生这种情况)
    • 如果您的服务是托管在 IIS 中的 ASP.NET Web API 服务,那么传入请求的默认设置是缓冲正文,因此您需要更改 IHostBufferPolicySelector 服务使请求正文不被缓冲...例如:stackoverflow.com/questions/12699364/… ..
    • 我已经在使用 IHostBufferPolicySelector,但这不是我的问题。我检查了接口方法的调用,但是直到客户端发送请求才调用它。我也将 Web api 作为服务托管(自托管)。在那里我注意到我的 web api 得到了流——即使客户端使用 TransferEncodingChunked = true。 (网络托管的网络 api 得到一个没有内容的流)。我还注意到与网络托管不同。我得到的流是不可搜索的,所以我必须改变我的方法,它使用了长度属性。但仍然:分块不起作用。客户必须写...
    • ... 整个日期到流并且必须调用 stream.close() 然后 HttpClient 发送请求。所以我认为客户端有问题。我必须配置的东西,否则......基本上,http-clients是否有可能在服务器仍在处理请求(并且正在读取流)之后(或同时)通过流发送数据。 HttpClient 是否支持“PushStreamContent”?我不得不添加一个额外的参考。在那之前,HttpClient 不知道“PushStreamContent”。
    • 您能分享一下您的 WriteToStream 实现吗?
    猜你喜欢
    • 1970-01-01
    • 2014-08-22
    • 2013-04-16
    • 2018-10-08
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多