当http状态代码400(错误请求)返回时,.Net HttpWebRequest.GetResponse()会引发异常。

时间:2021-07-06 18:33:23

I am in a situation where when I get an HTTP 400 code from the server, it is a completely legal way of the server telling me what was wrong with my request (using a message in the HTTP response content)

我的情况是,当我从服务器获得HTTP 400代码时,它是服务器的完全合法的方式,告诉我我的请求有什么问题(在HTTP响应内容中使用消息)

However, the .NET HttpWebRequest raises an exception when the status code is 400.

然而,当状态代码为400时,. net HttpWebRequest引发了一个异常。

How do I handle this? For me a 400 is completely legal, and rather helpful. The HTTP content has some important information but the exception throws me off my path.

我要怎么处理?对我来说,400是完全合法的,而且相当有帮助。HTTP内容有一些重要的信息,但是例外情况使我偏离了我的路径。

6 个解决方案

#1


300  

It would be nice if there were some way of turning off "throw on non-success code" but if you catch WebException you can at least use the response:

如果有一些方法可以关闭“非成功代码”,那就太好了,但是如果你发现了WebException,你至少可以使用响应:

using System;
using System.IO;
using System.Web;
using System.Net;

public class Test
{
    static void Main()
    {
        WebRequest request = WebRequest.Create("http://csharpindepth.com/asd");
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                Console.WriteLine("Won't get here");
            }
        }
        catch (WebException e)
        {
            using (WebResponse response = e.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse) response;
                Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                using (Stream data = response.GetResponseStream())
                using (var reader = new StreamReader(data))
                {
                    string text = reader.ReadToEnd();
                    Console.WriteLine(text);
                }
            }
        }
    }
}

You might like to encapsulate the "get me a response even if it's not a success code" bit in a separate method. (I'd suggest you still throw if there isn't a response, e.g. if you couldn't connect.)

您可能喜欢将“get me a response”封装在一个单独的方法中,即使它不是一个成功的代码。(如果没有回应,我建议你还是放弃,例如如果你不能联系。)

If the error response may be large (which is unusual) you may want to tweak HttpWebRequest.DefaultMaximumErrorResponseLength to make sure you get the whole error.

如果错误响应可能很大(这是不正常的),您可能需要调整HttpWebRequest。DefaultMaximumErrorResponseLength确保您得到整个错误。

#2


40  

I know this has already been answered a long time ago, but I made an extension method to hopefully help other people that come to this question.

我知道这个问题很久以前就已经回答过了,但是我做了一个扩展的方法来帮助其他人解决这个问题。

Code:

代码:

public static class WebRequestExtensions
{
    public static WebResponse GetResponseWithoutException(this WebRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        try
        {
            return request.GetResponse();
        }
        catch (WebException e)
        {
            if (e.Response == null)
            {
                throw;
            }

            return e.Response;
        }
    }
}

Usage:

用法:

var request = (HttpWebRequest)WebRequest.CreateHttp("http://invalidurl.com");

//... (initialize more fields)

using (var response = (HttpWebResponse)request.GetResponseWithoutException())
{
    Console.WriteLine("I got Http Status Code: {0}", response.StatusCode);
}

#3


10  

Interestingly, the HttpWebResponse.GetResponseStream() that you get from the WebException.Response is not the same as the response stream that you would have received from server. In our environment, we're losing actual server responses when a 400 HTTP status code is returned back to the client using the HttpWebRequest/HttpWebResponse objects. From what we've seen, the response stream associated with the WebException's HttpWebResponse is generated at the client and does not include any of the response body from the server. Very frustrating, as we want to message back to the client the reason for the bad request.

有趣的是,HttpWebResponse.GetResponseStream()从WebException中得到。响应与您从服务器接收到的响应流不一样。在我们的环境中,当使用HttpWebRequest/HttpWebResponse对象将400个HTTP状态代码返回给客户机时,我们正在失去实际的服务器响应。从我们所看到的情况来看,与WebException的HttpWebResponse相关的响应流是在客户端生成的,并且不包括来自服务器的任何响应主体。非常令人沮丧,因为我们想要向客户反馈坏请求的原因。

#4


9  

I had similar issues when trying to connect to Google's OAuth2 service.

我在尝试连接谷歌的OAuth2服务时遇到了类似的问题。

I ended up writing the POST manually, not using WebRequest, like this:

我最后手工写了这篇文章,不是用WebRequest,像这样:

TcpClient client = new TcpClient("accounts.google.com", 443);
Stream netStream = client.GetStream();
SslStream sslStream = new SslStream(netStream);
sslStream.AuthenticateAsClient("accounts.google.com");

{
    byte[] contentAsBytes = Encoding.ASCII.GetBytes(content.ToString());

    StringBuilder msg = new StringBuilder();
    msg.AppendLine("POST /o/oauth2/token HTTP/1.1");
    msg.AppendLine("Host: accounts.google.com");
    msg.AppendLine("Content-Type: application/x-www-form-urlencoded");
    msg.AppendLine("Content-Length: " + contentAsBytes.Length.ToString());
    msg.AppendLine("");
    Debug.WriteLine("Request");
    Debug.WriteLine(msg.ToString());
    Debug.WriteLine(content.ToString());

    byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
    sslStream.Write(headerAsBytes);
    sslStream.Write(contentAsBytes);
}

Debug.WriteLine("Response");

StreamReader reader = new StreamReader(sslStream);
while (true)
{  // Print the response line by line to the debug stream for inspection.
    string line = reader.ReadLine();
    if (line == null) break;
    Debug.WriteLine(line);
}

The response that gets written to the response stream contains the specific error text that you're after.

写到响应流的响应包含您要处理的特定错误文本。

In particular, my problem was that I was putting endlines between url-encoded data pieces. When I took them out, everything worked. You might be able to use a similar technique to connect to your service and read the actual response error text.

特别是,我的问题是,我在url编码的数据块之间设置了endlines。当我把它们拿出来的时候,一切都很正常。您可能可以使用类似的技术来连接到您的服务,并读取实际的响应错误文本。

#5


4  

Try this (it's VB-Code :-):

试试这个(它是VB-Code:-):

Catch exp As WebException

    'Read the real response from the server
    Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd

#6


2  

An asynchronous version of extension function:

一个异步版本的扩展函数:

    public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
    {
        try
        {
            return await request.GetResponseAsync();
        }
        catch(WebException ex)
        {
            return ex.Response;
        }
    }

#1


300  

It would be nice if there were some way of turning off "throw on non-success code" but if you catch WebException you can at least use the response:

如果有一些方法可以关闭“非成功代码”,那就太好了,但是如果你发现了WebException,你至少可以使用响应:

using System;
using System.IO;
using System.Web;
using System.Net;

public class Test
{
    static void Main()
    {
        WebRequest request = WebRequest.Create("http://csharpindepth.com/asd");
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                Console.WriteLine("Won't get here");
            }
        }
        catch (WebException e)
        {
            using (WebResponse response = e.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse) response;
                Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                using (Stream data = response.GetResponseStream())
                using (var reader = new StreamReader(data))
                {
                    string text = reader.ReadToEnd();
                    Console.WriteLine(text);
                }
            }
        }
    }
}

You might like to encapsulate the "get me a response even if it's not a success code" bit in a separate method. (I'd suggest you still throw if there isn't a response, e.g. if you couldn't connect.)

您可能喜欢将“get me a response”封装在一个单独的方法中,即使它不是一个成功的代码。(如果没有回应,我建议你还是放弃,例如如果你不能联系。)

If the error response may be large (which is unusual) you may want to tweak HttpWebRequest.DefaultMaximumErrorResponseLength to make sure you get the whole error.

如果错误响应可能很大(这是不正常的),您可能需要调整HttpWebRequest。DefaultMaximumErrorResponseLength确保您得到整个错误。

#2


40  

I know this has already been answered a long time ago, but I made an extension method to hopefully help other people that come to this question.

我知道这个问题很久以前就已经回答过了,但是我做了一个扩展的方法来帮助其他人解决这个问题。

Code:

代码:

public static class WebRequestExtensions
{
    public static WebResponse GetResponseWithoutException(this WebRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        try
        {
            return request.GetResponse();
        }
        catch (WebException e)
        {
            if (e.Response == null)
            {
                throw;
            }

            return e.Response;
        }
    }
}

Usage:

用法:

var request = (HttpWebRequest)WebRequest.CreateHttp("http://invalidurl.com");

//... (initialize more fields)

using (var response = (HttpWebResponse)request.GetResponseWithoutException())
{
    Console.WriteLine("I got Http Status Code: {0}", response.StatusCode);
}

#3


10  

Interestingly, the HttpWebResponse.GetResponseStream() that you get from the WebException.Response is not the same as the response stream that you would have received from server. In our environment, we're losing actual server responses when a 400 HTTP status code is returned back to the client using the HttpWebRequest/HttpWebResponse objects. From what we've seen, the response stream associated with the WebException's HttpWebResponse is generated at the client and does not include any of the response body from the server. Very frustrating, as we want to message back to the client the reason for the bad request.

有趣的是,HttpWebResponse.GetResponseStream()从WebException中得到。响应与您从服务器接收到的响应流不一样。在我们的环境中,当使用HttpWebRequest/HttpWebResponse对象将400个HTTP状态代码返回给客户机时,我们正在失去实际的服务器响应。从我们所看到的情况来看,与WebException的HttpWebResponse相关的响应流是在客户端生成的,并且不包括来自服务器的任何响应主体。非常令人沮丧,因为我们想要向客户反馈坏请求的原因。

#4


9  

I had similar issues when trying to connect to Google's OAuth2 service.

我在尝试连接谷歌的OAuth2服务时遇到了类似的问题。

I ended up writing the POST manually, not using WebRequest, like this:

我最后手工写了这篇文章,不是用WebRequest,像这样:

TcpClient client = new TcpClient("accounts.google.com", 443);
Stream netStream = client.GetStream();
SslStream sslStream = new SslStream(netStream);
sslStream.AuthenticateAsClient("accounts.google.com");

{
    byte[] contentAsBytes = Encoding.ASCII.GetBytes(content.ToString());

    StringBuilder msg = new StringBuilder();
    msg.AppendLine("POST /o/oauth2/token HTTP/1.1");
    msg.AppendLine("Host: accounts.google.com");
    msg.AppendLine("Content-Type: application/x-www-form-urlencoded");
    msg.AppendLine("Content-Length: " + contentAsBytes.Length.ToString());
    msg.AppendLine("");
    Debug.WriteLine("Request");
    Debug.WriteLine(msg.ToString());
    Debug.WriteLine(content.ToString());

    byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
    sslStream.Write(headerAsBytes);
    sslStream.Write(contentAsBytes);
}

Debug.WriteLine("Response");

StreamReader reader = new StreamReader(sslStream);
while (true)
{  // Print the response line by line to the debug stream for inspection.
    string line = reader.ReadLine();
    if (line == null) break;
    Debug.WriteLine(line);
}

The response that gets written to the response stream contains the specific error text that you're after.

写到响应流的响应包含您要处理的特定错误文本。

In particular, my problem was that I was putting endlines between url-encoded data pieces. When I took them out, everything worked. You might be able to use a similar technique to connect to your service and read the actual response error text.

特别是,我的问题是,我在url编码的数据块之间设置了endlines。当我把它们拿出来的时候,一切都很正常。您可能可以使用类似的技术来连接到您的服务,并读取实际的响应错误文本。

#5


4  

Try this (it's VB-Code :-):

试试这个(它是VB-Code:-):

Catch exp As WebException

    'Read the real response from the server
    Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd

#6


2  

An asynchronous version of extension function:

一个异步版本的扩展函数:

    public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request)
    {
        try
        {
            return await request.GetResponseAsync();
        }
        catch(WebException ex)
        {
            return ex.Response;
        }
    }