2009-03-28 45 views
171

Tôi đang trong tình huống khi tôi nhận được mã HTTP 400 từ máy chủ, đó là cách hoàn toàn hợp pháp của máy chủ tôi những gì là sai trái với yêu cầu của tôi (sử dụng một thông điệp trong nội dung HTTP response).Net HttpWebRequest.GetResponse() tăng ngoại lệ khi mã trạng thái http 400 (yêu cầu xấu) được trả về

Tuy nhiên, NET HttpWebRequest đặt ra một ngoại lệ khi các mã trạng thái là 400.

làm thế nào để xử lý này? Đối với tôi, 400 là hoàn toàn hợp pháp, và khá hữu ích. Nội dung HTTP có một số thông tin quan trọng nhưng ngoại lệ đã ném tôi ra khỏi đường dẫn của tôi.

+6

Tôi đã trải qua điều tương tự. Tôi đã gửi một đề xuất cho nhóm .NET Framework. Vui lòng bỏ phiếu cho nó: https://connect.microsoft.com/VisualStudio/feedback/details/575075/no-exception-on-httpwebrequest-getresponse#details –

Trả lời

294

Nó sẽ được tốt đẹp nếu có một số cách để tắt "ném vào mã không thành công" nhưng nếu bạn bắt WebException bạn ít nhất có thể sử dụng các phản ứng:

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

Bạn có thể muốn để đóng gói các "cho tôi một phản ứng ngay cả khi nó không phải là một mã thành công" bit trong một phương pháp riêng biệt. (Tôi khuyên bạn vẫn nên ném nếu không có phản hồi, ví dụ: nếu bạn không thể kết nối.)

Nếu phản hồi lỗi có thể lớn (bất thường) bạn có thể muốn tinh chỉnh HttpWebRequest.DefaultMaximumErrorResponseLength để đảm bảo bạn nhận được toàn bộ lỗi.

+8

+ 1 Tôi đã ném lên cố gắng tìm ra lý do tại sao điều này đã xảy ra – hunter

+3

Nội dung của luồng được trả về bởi GetResponseStream() trên phản hồi gắn với WebException chỉ là tên của mã trạng thái (ví dụ "Yêu cầu Xấu") thay vì phản hồi thực sự được máy chủ trả về. Có cách nào để lấy thông tin này không? –

+0

@MarkWatts: Nó * nên * là bất kỳ cái gì được trả về bởi máy chủ, và đã ở trong mọi tình huống tôi đã thấy. Bạn có thể sao chép điều này với một URL bên ngoài cụ thể không? Tôi đề nghị bạn hỏi một câu hỏi mới (đề cập đến câu hỏi này) và cho thấy những gì đang xảy ra. –

10

Điều thú vị là HttpWebResponse.GetResponseStream() mà bạn nhận được từ WebException.Response không giống như luồng phản hồi mà bạn đã nhận được từ máy chủ. Trong môi trường của chúng tôi, chúng tôi đang mất các phản hồi máy chủ thực tế khi mã trạng thái 400 HTTP được trả lại cho máy khách bằng cách sử dụng các đối tượng HttpWebRequest/HttpWebResponse. Từ những gì chúng ta đã thấy, luồng phản hồi kết hợp với HttpWebResponse của WebException được tạo ra ở máy khách và không bao gồm bất kỳ phần thân phản hồi nào từ máy chủ. Rất bực bội, vì chúng tôi muốn nhắn tin lại cho khách hàng lý do cho yêu cầu xấu.

9

Tôi gặp sự cố tương tự khi cố gắng kết nối với dịch vụ OAuth2 của Google.

tôi đã kết thúc bằng văn bản cho POST bằng tay, không sử dụng WebRequest, như thế này:

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

Câu trả lời đó được ghi vào dòng phản ứng chứa văn bản lỗi cụ thể mà bạn đang theo đuổi.

Cụ thể, vấn đề của tôi là tôi đã đặt dòng cuối cùng giữa các phần dữ liệu được mã hóa bằng url. Khi tôi lấy chúng ra, mọi thứ đều hiệu quả. Bạn có thể sử dụng một kỹ thuật tương tự để kết nối với dịch vụ của bạn và đọc văn bản lỗi phản hồi thực tế.

+0

HttpWebRequest là như vậy sai lầm. Ngay cả ổ cắm được dễ dàng hơn (coz họ không giấu lỗi đi từ bạn). –

40

Tôi biết điều này đã được trả lời từ lâu rồi, nhưng tôi đã thực hiện một phương pháp mở rộng để hy vọng giúp đỡ những người khác đến với câu hỏi này.

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

Cách sử dụng:

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

'WebException.Response' có thể và có thể là' null'. Bạn nên nghĩ lại nếu đây là trường hợp. –

+0

@IanKemp Đề xuất hay, cập nhật. – Matthew

+0

Tuyệt vời! Bạn sẽ nghĩ rằng đây sẽ là một tùy chọn được xây dựng cho GetResponse() –

4

Hãy thử điều này (nó VB-Code :-):

Catch exp As WebException 

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

Một phiên bản không đồng bộ của chức năng mở rộng :

public static async Task<WebResponse> GetResponseAsyncNoEx(this WebRequest request) 
    { 
     try 
     { 
      return await request.GetResponseAsync(); 
     } 
     catch(WebException ex) 
     { 
      return ex.Response; 
     } 
    } 
Các vấn đề liên quan