簡體   English   中英

HttpWebRequest chunked / async POST

[英]HttpWebRequest chunked/async POST

嗨,我想將一些動態生成的內容上傳到我的網絡API。 在客戶端我使用HttpWebRequest。 數據應該上傳同步,我想寫入流AFTER(!)我執行了HTTP請求。

(從服務器到客戶端它確實工作正常,但從客戶端到服務器我得到一些例外)。

客戶端實現如下:

HttpWebRequest httpWebRequest = HttpWebRequest.Create(myUrl) as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.Headers["Authorization"] = "Basic " + ... ;
httpWebRequest.PreAuthenticate = true;

httpWebRequest.SendChunked = true;
//httpWebRequest.AllowWriteStreamBuffering = false; //does not help...
httpWebRequest.ContentType = "application/octet-stream";
Stream st = httpWebRequest.GetRequestStream();

Task<WebResponse> response = httpWebRequest.GetResponseAsync();

// NOW: Write after GetResponse()

var b = Encoding.UTF8.GetBytes("Test1");
st.Write(b, 0, b.Length);

b = Encoding.UTF8.GetBytes("Test2");
st.Write(b, 0, b.Length);

b = Encoding.UTF8.GetBytes("Test3");
st.Write(b, 0, b.Length);

st.Close();

var x = response.Result;
Stream resultStream = x.GetResponseStream();
//do some output...

我在stream.write()上得到異常(NotSupportedException:流不支持並發IO讀或寫操作。)。

為什么我這里有例外。 有時第一次寫入worke而后期寫入會拋出異常。 在開始時,stream.CanWrite屬性為true,但在第一次或第二次或第四次寫入后,它變為false ...然后在下一次寫入時拋出異常。

編輯:更改AllowWriteStreamBuffering沒有幫助

附錄: 我發現了我的問題。 此問題是由我的代碼的順序引起的。 我必須按此順序調用它:

  • GetRequestStream(將異步寫入流)(請求在第一次寫入后發送到服務器)然后:
  • GetResponseAsync()
  • 的GetResponseStream()

我認為“GetResponseAsync”會觸發客戶端發送請求(現在只有標頭)。 但是沒有必要,因為在我將第一個比特寫入流后,請求已經發送。

我問題的第二個原因:提琴手。 (Fiddler目前僅支持響應流而不是請求)

我發現了我的問題。

我的代碼順序導致了問題。

解決方案是按此順序調用它:

  • GetRequestStream(將異步寫入流)(請求在第一次寫入后發送到服務器)然后:
  • GetResponseAsync()
  • 的GetResponseStream()

我的理解是“GetResponseAsync”觸發客戶端發送請求(現在只是頭文件),但我發現它是一個不成功的步驟,因為請求已經在最初的幾位寫入之后發送了流。

我的問題的第二個原因是Fiddler,但Fiddler只支持響應流,而不支持請求。

該代碼實現了引用,'HttpWebRequest'類:

HttpWebRequest httpWebRequest = HttpWebRequest.Create("http://xxx") as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("user:pw"));
httpWebRequest.PreAuthenticate = true;    
httpWebRequest.SendChunked = true;
httpWebRequest.AllowWriteStreamBuffering = false;
httpWebRequest.AllowReadStreamBuffering = false;    
httpWebRequest.ContentType = "application/octet-stream";

Stream st = httpWebRequest.GetRequestStream();

Console.WriteLine("Go");

try
{
    st.Write(buffer, 0, buffer.Length); //with the first write, the request will be send.
    st.Write(buffer, 0, buffer.Length);
    st.Write(buffer, 0, buffer.Length);

    for (int i = 1; i <= 10; i++)
    {        
        st.Write(buffer, 0, buffer.Length); //still writing while I can read on the stream at my ASP.NET web api

    }

}
catch (WebException ex)
{
    var y = ex.Response;

}
finally
{
    st.Close();

}

// Now we can read the response from the server in chunks

Task<WebResponse> response = httpWebRequest.GetResponseAsync();

Stream resultStream = response.Result.GetResponseStream();

byte[] data = new byte[1028];

int bytesRead;

while ((bytesRead = resultStream.Read(data, 0, data.Length)) > 0)
{
    string output = System.Text.Encoding.UTF8.GetString(data, 0, bytesRead);

    Console.WriteLine(output);

}

該代碼實現了引用,'HttpClient'類:

HttpClientHandler ch = new HttpClientHandler();

HttpClient c = new HttpClient(ch);    
c.DefaultRequestHeaders.TransferEncodingChunked = true;    
c.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes("user:pw")));

Stream stream = new MemoryStream();

AsyncStream asyncStream = new AsyncStream(); // Custom implementation of the PushStreamContent with the method, "WriteToStream()".

PushStreamContent streamContent = new PushStreamContent(asyncStream.WriteToStream);

HttpRequestMessage requestMessage = new HttpRequestMessage(new HttpMethod("POST"), "http://XXX") { Content = streamContent };

requestMessage.Headers.TransferEncodingChunked = true;

HttpResponseMessage response = await c.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);

// The request has been sent, since the first write in the "WriteToStream()" method.

response.EnsureSuccessStatusCode();

Task<Stream> result = response.Content.ReadAsStreamAsync();

byte[] data = new byte[1028];

int bytesRead;

while ((bytesRead = await result.Result.ReadAsync(data, 0, data.Length)) > 0)
{
    string output = System.Text.Encoding.UTF8.GetString(data, 0, bytesRead);

    Console.WriteLine(output);

}

Console.ReadKey();

您正在同時在多個線程上使用HttpWebRequest對象。 response是與您的寫入同時運行的任務。 這顯然是線程不安全的。

另外,我看不到你想要達到的目標。 HTTP具有請求然后響應模型。 在接收整個請求之前,服務器不能(通常)發送單個響應字節。 從理論上講,這是可能的。 但這很不尋常,可能不受.NET BCL的支持。 這只能由您的(非常不尋常的)自定義HTTP服務器支持。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM