簡體   English   中英

.Net HttpWebRequest.GetResponse() 在返回 http 狀態代碼 400(錯誤請求)時引發異常

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

我遇到的情況是,當我從服務器獲取 HTTP 400 代碼時,服務器告訴我我的請求出了什么問題是一種完全合法的方式(使用 HTTP 響應內容中的消息)

但是,當狀態代碼為 400 時,.NET HttpWebRequest 會引發異常。

我該如何處理? 對我來說,400 是完全合法的,而且很有幫助。 HTTP 內容包含一些重要信息,但異常使我偏離了路徑。

如果有某種方法可以關閉“拋出非成功代碼”,那就太好了,但是如果您捕獲 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);
                }
            }
        }
    }
}

您可能希望在單獨的方法中封裝“即使它不是成功代碼也給我一個響應”位。 (如果沒有響應,我建議您仍然拋出,例如,如果您無法連接。)

如果錯誤響應可能很大(這是不尋常的),您可能需要調整HttpWebRequest.DefaultMaximumErrorResponseLength以確保您得到整個錯誤。

我知道很久以前就已經回答了這個問題,但是我做了一個擴展方法,希望能幫助到這個問題的其他人。

代碼:

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

用法:

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

有趣的是,您從WebException.Response獲得的HttpWebResponse.GetResponseStream()與您從服務器收到的響應流不同。 在我們的環境中,當使用HttpWebRequest/HttpWebResponse對象將400 HTTP 狀態代碼返回給客戶端時,我們會丟失實際的服務器響應。 從我們所見,與WebException's HttpWebResponse關聯的響應流是在客戶端生成的,不包括來自服務器的任何響應正文。 非常令人沮喪,因為我們想將錯誤請求的原因反饋給客戶端。

我在嘗試連接到 Google 的 OAuth2 服務時遇到了類似的問題。

我最終手動編寫了 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);
}

寫入響應流的響應包含您要查找的特定錯誤文本。

特別是,我的問題是我在 url 編碼的數據段之間放置了結束線。 當我把它們拿出來時,一切正常。 您或許可以使用類似的技術連接到您的服務並閱讀實際的響應錯誤文本。

試試這個(它是 VB 代碼 :-):

Try

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

一個異步版本的擴展函數:

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

這為我解決了:
https://gist.github.com/beccasaurus/929007/a8f820b153a1cfdee3d06a9c0a1d7ebfced8bb77

特爾;博士:
問題:
本地主機返回預期內容,遠程 IP 將 400 內容更改為“錯誤請求”
解決方案:
<httpErrors existingResponse="PassThrough"></httpErrors>web.config/configuration/system.webServer為我解決了這個問題; 現在,無論我返回的 IP 地址和/或 HTTP 代碼如何,所有服務器(本地和遠程)都返回完全相同的內容(由我生成)。

暫無
暫無

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

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