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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/692342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:25:49  来源:igfitidea点击:

.Net HttpWebRequest.GetResponse() raises exception when http status code 400 (bad request) is returned

.nethttpwebrequest

提问by chefsmart

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 内容包含一些重要信息,但异常使我偏离了路径。

回答by Jon Skeet

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.)

您可能希望在单独的方法中封装“即使它不是成功代码也给我一个响应”位。(如果没有响应,我建议您仍然抛出,例如,如果您无法连接。)

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

如果错误响应可能很大(这是不寻常的),您可能需要进行调整HttpWebRequest.DefaultMaximumErrorResponseLength以确保获得整个错误。

回答by Matthew

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);
}

回答by Christopher Bartling

Interestingly, the HttpWebResponse.GetResponseStream()that you get from the WebException.Responseis 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 statuscode is returned back to the client using the HttpWebRequest/HttpWebResponseobjects. From what we've seen, the response stream associated with the WebException's HttpWebResponseis 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.Response的 与您从服务器收到的响应流不同。在我们的环境中,当使用对象将400 HTTP 状态代码返回给客户端时,我们会丢失实际的服务器响应HttpWebRequest/HttpWebResponse。从我们所见,与 相关联的响应流WebException's HttpWebResponse是在客户端生成的,不包括来自服务器的任何响应正文。非常令人沮丧,因为我们想将错误请求的原因反馈给客户端。

回答by Jugglist

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

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

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

我最终手动编写了 POST,而不是使用 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 编码的数据段之间放置了结束线。当我把它们拿出来时,一切正常。您或许可以使用类似的技术连接到您的服务并阅读实际的响应错误文本。

回答by Bernd

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

试试这个(它是 VB 代码 :-):

Try

Catch exp As WebException
  Dim sResponse As String = New StreamReader(exp.Response.GetResponseStream()).ReadToEnd
End Try

回答by Jason Hu

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;
        }
    }

回答by dlchambers

This solved it for me:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

这为我解决了:https:
//gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

TL;DR:
Problem:
localhost returns expected content, remote IP alters 400 content to "Bad Request"
Solution:
Adding <httpErrors existingResponse="PassThrough"></httpErrors>to web.config/configuration/system.webServersolved this for me; now all servers (local & remote) return the exact same content (generated by me) regardless of the IP address and/or HTTP code I return.

TL;DR:
问题:
本地主机返回预期内容,远程 IP 将 400 内容更改为“错误请求”
解决方案:
添加<httpErrors existingResponse="PassThrough"></httpErrors>web.config/configuration/system.webServer解决此问题;现在,无论我返回的 IP 地址和/或 HTTP 代码如何,所有服务器(本地和远程)都返回完全相同的内容(由我生成)。