【问题标题】:WebException how to get whole response with a body?WebException 如何通过正文获得整个响应?
【发布时间】:2012-08-03 10:58:27
【问题描述】:

在 WebException 中,我看不到 GetResponse 的正文。这是我在 C# 中的代码:

try {                
  return GetResponse(url + "." + ext.ToString(), method, headers, bodyParams);
} catch (WebException ex) {
    switch (ex.Status) {
      case WebExceptionStatus.ConnectFailure:
         throw new ConnectionException();                        
     case WebExceptionStatus.Timeout:
         throw new RequestTimeRanOutException();                     
     case WebExceptionStatus.NameResolutionFailure:
         throw new ConnectionException();                        
     case WebExceptionStatus.ProtocolError:
          if (ex.Message == "The remote server returned an error: (401) unauthorized.") {
              throw new CredentialsOrPortalException();
          }
          throw new ProtocolErrorExecption();                    
     default:
          throw;
    }

我看到标题但我没有看到正文。这是 Wireshark 针对请求的输出:

POST /api/1.0/authentication.json HTTP/1.1    
Content-Type: application/x-www-form-urlencoded    
Accept: application/json    
Host: nbm21tm1.teamlab.com    
Content-Length: 49    
Connection: Keep-Alive    

userName=XXX&password=YYYHTTP/1.1 500 Server error    
Cache-Control: private, max-age=0    
Content-Length: 106    
Content-Type: application/json; charset=UTF-8    
Server: Microsoft-IIS/7.5    
X-AspNet-Version: 2.0.50727    
X-Powered-By: ASP.NET    
X-Powered-By: ARR/2.5

Date: Mon, 06 Aug 2012 12:49:41 GMT    
Connection: close    

{"count":0,"startIndex":0,"status":1,"statusCode":500,"error":{"message":"Invalid username or password."}}

是否有可能在 WebException 中看到消息文本? 谢谢。

【问题讨论】:

  • 你试过了吗(HttpWebResponse)we.Response;你捕获的 WebException 在哪里“我们”?
  • 要在重新抛出的异常中保留堆栈跟踪,不要使用throw ex;,而只需使用throw;(在默认情况下)。另外(如果需要)我会将原始 WebException 放在您的自定义异常的 InnerException 中(通过适当的构造函数)。

标签: c# webexception


【解决方案1】:
var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();

dynamic obj = JsonConvert.DeserializeObject(resp);
var messageFromServer = obj.error.message;

【讨论】:

  • 对于不熟悉 JsonConvert 的人,您需要从 nuget 包管理器获取 Newtonsoft.Json。
  • 请用凯尔的解释更新答案,因为 Newtonsoft.Json 是可选的。
  • 另外,请说明此代码应位于请求应进入的 Try-Catch 代码块的 Catch 后备子句中。我知道对于这种情况,对于关注的读者和@iwtu 来说很明显,但是完全全面的答案可以对阅读此答案的初学者产生真正的影响;)
  • StreamReader 实现了 IDisposable,所以将其包装在 using 语句中不是最佳做法吗?快速查看 StreamReader 的 Dispose 方法表明它在其中做了一些重要的清理工作。
  • @sammy34 不用担心,因为这里没有非托管代码/数据在这种情况下,垃圾收集器可以轻松处理它......(但使用 using 总是一个好习惯)
【解决方案2】:
try {
 WebClient client = new WebClient();
 client.Encoding = Encoding.UTF8;
 string content = client.DownloadString("https://sandiegodata.atlassian.net/wiki/pages/doaddcomment.action?pageId=524365");
 Console.WriteLine(content);
 Console.ReadKey();
} catch (WebException ex) {
 var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
 Console.WriteLine(resp);
 Console.ReadKey();
}

【讨论】:

    【解决方案3】:

    这只改进了现有的答案。我编写了一个方法,它使用增强的消息处理投掷/重新投掷的细节,其中包括响应正文:

    这是我的代码(在 Client.cs 中):

    /// <summary>
    ///     Tries to rethrow the WebException with the data from the body included, if possible. 
    ///     Otherwise just rethrows the original message.
    /// </summary>
    /// <param name="wex">The web exception.</param>
    /// <exception cref="WebException"></exception>
    /// <remarks>
    ///     By default, on protocol errors, the body is not included in web exceptions. 
    ///     This solutions includes potentially relevant information for resolving the
    ///     issue.
    /// </remarks>
    private void ThrowWithBody(WebException wex) {
        if (wex.Status == WebExceptionStatus.ProtocolError) {
            string responseBody;
            try {
                //Get the message body for rethrow with body included
                responseBody = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
    
            } catch (Exception) {
                //In case of failure to get the body just rethrow the original web exception.
                throw wex;
            }
    
            //include the body in the message
            throw new WebException(wex.Message + $" Response body: '{responseBody}'", wex, wex.Status, wex.Response);
        }
    
        //In case of non-protocol errors no body is available anyway, so just rethrow the original web exception.
        throw wex;
    }
    

    您在 catch 子句中使用它,就像 OP 显示的那样:

    //Execute Request, catch the exception to eventually get the body
    try {
        //GetResponse....
        }
    } catch (WebException wex) {
        if (wex.Status == WebExceptionStatus.ProtocolError) {
            ThrowWithBody(wex);
        }
    
        //otherwise rethrow anyway
        throw;
    }
    

    【讨论】:

      【解决方案4】:

      我没有看到using 语句的任何答案,也没有看到async 的任何用途。

      public static class WebExceptionExtensions
      {
          public static string GetResponseBody(this WebException webException)
          {
              if (webException.Status == WebExceptionStatus.ProtocolError)
              {
                  try
                  {
                      using (var stream = webException.Response.GetResponseStream())
                      {
                          using (var reader = new StreamReader(stream))
                          {
                              string msg = reader.ReadToEnd();
                              if (string.IsNullOrEmpty(msg) && webException.Response is HttpWebResponse response)
                                  msg = $"{response.StatusDescription} ({(int)response.StatusCode})"; // provide some error message if not found
      
                              return msg;
                          }
                      }
                  }
                  catch (WebException) // we tried
                  {
                      return string.Empty;
                  }
              }
              else
              {
                  return string.Empty;
              }
          }
      
          public static async Task<string> GetResponseBodyAsync(this WebException webException)
          {
              if (webException.Status == WebExceptionStatus.ProtocolError)
              {
                  try
                  {
                      using (var stream = webException.Response.GetResponseStream())
                      {
                          using (var reader = new StreamReader(stream))
                          {
                              string msg = await reader.ReadToEndAsync();
                              if (string.IsNullOrEmpty(msg) && webException.Response is HttpWebResponse response)
                                  msg = $"{response.StatusDescription} ((int){response.StatusCode})"; // provide some error message if not found
      
                              return msg;
                          }
                      }
                  }
                  catch (WebException) //  we tried
                  {
                      return string.Empty;
                  }
              }
              else
              {
                  return string.Empty;
              }
          }
      }
      

      现在,每当我们捕获 WebExceptions 时,就很容易获得响应体。

      try 
      {
          // Do work here...
      }
      catch (WebException we)
      {
          Console.WriteLine(we.GetResponseBody()); // synchronous
          Console.WriteLine(await we.GetResponseBodyAsync()); // or asynchronous
      }
      catch (Exception e)
      {
          throw new Exception("Unexpected error occured", e);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-04
        • 1970-01-01
        • 2011-07-02
        • 1970-01-01
        相关资源
        最近更新 更多