HttpWebRequest.GetRequestStream : What it does?

2019-03-08 10:32发布

问题:

Code exemple:

HttpWebRequest request =
   (HttpWebRequest)HttpWebRequest.Create("http://some.existing.url");

request.Method = "POST";
request.ContentType = "text/xml";

Byte[] documentBytes = GetDocumentBytes ();


using (Stream requestStream = request.GetRequestStream())
{
   requestStream.Write(documentBytes, 0, documentBytes.Length);
   requestStream.Flush();
   requestStream.Close();
}

When I do request.GetRequestStream (), there's nothing to send in the request. From the name of the method, and the intellisense it shows ("Get System.IO.Stream to use to write request data"), nothing indicates that this line of code will connect to the distant server.
But it seems it does...

Can anyone explain to me what HttpWebRequest.GetRequestStream () exactly does ?

Thanks for your enlightenments.

回答1:

Getting the request stream does not trigger the post, but closing the stream does. Post data is sent to the server in the following way:

  1. A connection is opened to the host
  2. Send request and headers
  3. Write Post data
  4. Wait for a response.

The act of flushing and closing the stream is the final step, and once the input stream is closed (i.e. the client has sent what it needs to the server), then the server can return a response.



回答2:

You use GetRequestStream() to synchronously obtain a reference to the upload stream. It is only after you have finished writing to the stream that the actual request is send.

However, I would suggest that you use the BeginGetRequestStream method instead of GetRequestStream. BeginGetRequestStream performs asynchronously and don't lock the current thread while the stream is being obtained. You pass a callback and a context to the BeginGetRequestStream. In the callback, you can call EndGetRequestStream() to finally grab a reference and repeat the writing steps listed above (for synchronous behavior). Example:

context.Request.BeginGetRequestStream(new AsyncCallback(Foo), context);

public void Foo(IAsyncResult asyncResult)
    {
        Context context = (Context)asyncResult.AsyncState;
        try
        {
            HttpWebRequest request = context.Request;

            using (var requestStream = request.EndGetRequestStream(asyncResult))
            using (var writer = new StreamWriter(requestStream))
            {
                // write to the request stream
            }

            request.BeginGetResponse(new AsyncCallback(ProcessResponse), context);
        }

Be very careful with BeginGetRequestStream. It never times out, thus you must add additional logic to your program to recover from situations where GetRequestStream will throw a timeout exception.

In general, threads are cheap. The async Begin/End methods of HttpWebRequest are only worth using if you will have 10,000 or more concurrent requests; because implementing timeouts is very tricky and error-prone. In general, using BeginGetRequestStream is premature optimization unless you need significant performance gains.