我一直在尝试使用System.Net.Http.HttpClient
来发布一个更大的文件(+ 1GB),但它会引发SystemOutOfMemory
异常:
at System.Net.ScatterGatherBuffers.AllocateMemoryChunk(Int32 newSize)
at System.Net.ScatterGatherBuffers..ctor(Int64 totalSize)
at System.Net.ConnectStream.EnableWriteBuffering()
at System.Net.HttpWebRequest.SetRequestSubmitDone(ConnectStream submitStream)
at System.Net.Connection.CompleteStartRequest(Boolean onSubmitThread, HttpWebRequest request, TriState needReConnect)
at System.Net.Connection.SubmitRequest(HttpWebRequest request, Boolean forcedsubmit)
at System.Net.ServicePoint.SubmitRequest(HttpWebRequest request, String connName)
at System.Net.HttpWebRequest.SubmitRequest(ServicePoint servicePoint)
at System.Net.HttpWebRequest.BeginGetRequestStream(AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.StartGettingRequestStream(RequestState state)
at System.Net.Http.HttpClientHandler.PrepareAndStartContentUpload(RequestState state)
显然,HttpWebRequest
出现类似问题,如此处所述:http://support.microsoft.com/kb/908573。
有没有办法将基础网络请求的AllowWriteStreamBuffering
设置为false
?我找不到任何。
干杯,
答案 0 :(得分:3)
为了节省其他感兴趣的时间,我正在回答我自己的问题。
经过几次测试后,异常似乎与问题中讨论的HttpWebRequest
的问题相同。我使用Microsoft.AspNet.WebApi版本4.0.20710.0。
以下是两段相同的代码;前者在大文件上失败,而后者工作正常。
顺便说一下,尽管HttpClient
的整体好处问题变得非常明显: - )
HttpClient
var clientRef = new System.Net.Http.HttpClient(
new HttpClientHandler()
{
Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword)
});
clientRef.BaseAddress = new Uri(serverAddress);
clientRef.DefaultRequestHeaders.ExpectContinue = false;
clientRef.PostAsync(
MyFavoriteURL,
new System.Net.Http.StreamContent(inputStream)).ContinueWith(
requestTask =>
{
HttpResponseMessage response = requestTask.Result;
response.EnsureSuccessStatusCode();
}, TaskContinuationOptions.LongRunning).Wait();
HttpWebRequest
// Preauthenticate
var req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(MyFavoriteURL);
req.Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword);
req.Method = "POST";
req.PreAuthenticate = true;
req.Timeout = 10000;
using (var resp = (System.Net.HttpWebResponse)req.GetResponse())
{
if (resp.StatusCode != System.Net.HttpStatusCode.Accepted && resp.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception("Authentication error");
}
}
// Upload
req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(MyFavoriteURL);
req.Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword);
req.Method = "POST";
req.PreAuthenticate = true;
req.Timeout = 1200000;
req.ContentLength = inputStream.Length;
req.ContentType = "application/binary";
req.AllowWriteStreamBuffering = false;
req.Headers.ExpectContinue = false;
using (var reqStream = req.GetRequestStream())
{
inputStream.CopyTo(reqStream);
}
using (var resp = (System.Net.HttpWebResponse)req.GetResponse())
{
if (resp.StatusCode != System.Net.HttpStatusCode.Accepted && resp.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception("Error uploading document");
}
}
答案 1 :(得分:0)
我也遇到了大文件上传的同样问题。添加我的发现,以便它可以帮助某人。
HttpClient根据以下条件确定是否进行缓冲,
if( HttpRequestMessage.Headers.TransferEncodingChunked == true || HttpRequestMessage.Content.Headers.ContentLength != null )
{
//do streamed upload
}else
{
//do buffered upload.
}
我已将PushedStreamContent用作HttpRequestMessage.Content,因为我的服务器每个请求最多接受150 MB。一旦我将TransferEncodingChunked设置为True,内存峰值就会减少。
答案 2 :(得分:0)
我认为你有一个重复的标题,你可以删除前一个
req.Headers.Add("ExpectContinue", "false");
...
req.Headers.ExpectContinue = false;
答案 3 :(得分:0)
帮助我发送大文件而不通过“继电器控制器”进行缓冲
我开始工作的场景是:
客户端网络应用程序(spa等) - > RelayController - >存储http数据流的最终内容控制器
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://someurl/api/upload"),
Method = HttpMethod.Post,
};
request.Headers.TransferEncodingChunked = true;
request.Content = new StreamContent(Request.Body);
await httpClient.SendAsync(request);`
花了很多时间让它上班,得到了Prakash P的领导,他发布了httpclient流媒体与缓冲逻辑。