Copying Http Request InputStream

2019-03-28 05:27发布

问题:

I'm implementing a proxy action method that forwards the incoming web request and forwards it to another web page, adding a few headers. The action method works file for GET requests, but I'm still struggling with forwarding the incoming POST request.

The problem is that I don't know how to properly write the request body to the outgoing HTTP request stream.

Here's a shortened version of what I've got so far:

//the incoming request stream
var requestStream=HttpContext.Current.Request.InputStream;
//the outgoing web request
var webRequest = (HttpWebRequest)WebRequest.Create(url);
...

//copy incoming request body to outgoing request
if (requestStream != null && requestStream.Length>0)
            {
                long length = requestStream.Length;
                webRequest.ContentLength = length;
                requestStream.CopyTo(webRequest.GetRequestStream())                    
            }

//THE NEXT LINE THROWS A ProtocolViolationException
 using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
                {
                    ...
                }

As soon as I call GetResponse on the outgoing http request, I get the following exception:

ProtocolViolationException: You must write ContentLength bytes to the request stream before calling [Begin]GetResponse.

I don't understand why this is happening, since requestStream.CopyTo should have taken care of writing the right amount of bytes.

Any suggestions would be greatly appreciated.

Thanks,

Adrian

回答1:

Yes, .Net is very finicky about this. The way to solve the problem is to both flush and close the stream. In other words:

Stream webStream = null;

try
{
    //copy incoming request body to outgoing request
    if (requestStream != null && requestStream.Length>0)
    {
        long length = requestStream.Length;
        webRequest.ContentLength = length;
        webStream = webRequest.GetRequestStream();
        requestStream.CopyTo(webStream);
    }
}
finally
{
    if (null != webStream)
    {
        webStream.Flush();
        webStream.Close();    // might need additional exception handling here
    }
}

// No more ProtocolViolationException!
using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
{
    ...
}


回答2:

The answer @brian works, however, I found that once requestStream.CopyTo(stream) was called, it would fire off my HttpWebResponse. This was an issue since I wasn't quite ready to send the request. So if anyone is having an issue with not all of the request headers or other data being sent, it is because CopyTo is firing your request.



回答3:

try modifying the block inside if statement

long length = requestStream.Length;
webRequest.ContentLength = length;
requestStream.CopyTo(webRequest.GetRequestStream())

with

webRequest.Method = "POST";
webRequest.ContentLength = requestStream.Length;
webRequest.ContentType = "application/x-www-form-urlencoded";
Stream stream = webRequest.GetRequestStream();
requestStream.CopyTo(stream);
stream.Close();