【问题标题】:Can't get ResponseStream from WebException无法从 WebException 获取 ResponseStream
【发布时间】:2015-02-04 09:06:58
【问题描述】:

我有一个桌面客户端,它通过 Http 与服务器端通信。 当服务器在数据处理方面出现一些问题时,它会在 Http 响应正文中使用正确的 Http 代码(主要是 HTTP-400)返回 JSON 中的错误描述。

当我阅读 HTTP-200 响应时,一切都很好,并且此代码有效:

 using (var response = await httpRequest.GetResponseAsync(token))
                {
                    using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
                    {
                        return await reader.ReadToEndAsync();
                    }
                }

但是当发生错误并抛出并捕获 WebException 时,会出现以下代码:

 catch (WebException ex)
            {
                 if (ex.Status == WebExceptionStatus.ProtocolError)
                {                   
                    using (var response = (HttpWebResponse) ex.Response)
                    {
                        using (var stream = response.GetResponseStream())
                        {
                            using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                            {
                                var json = reader.ReadToEnd();
                            }
                        }
                    }
                }
            }

我已经对其进行了一些处理以使其工作,但接下来会发生: response.ContentLength 有效 (184) 但stream.Length 是 0 之后我无法读取json(它是"") 我什至不知道该去哪里找,因为一切看起来都应该可行。

可能是什么问题?

【问题讨论】:

    标签: c# .net httpwebresponse system.net.webexception


    【解决方案1】:

    经过一个月几乎每天的思考,我找到了解决方法。

    问题是WebException.Response.GetResponseStream() 返回的流与请求期间获得的流不完全相同(现在找不到指向 msdn 的链接),当我们捕获异常并读取此流时,实际响应流丢失了(或者类似的东西,真的不知道并且无法在网上找到任何信息,除了查看现在是开源的 CLRCore)。

    要保存实际响应直到捕获WebException,您必须在HttpRequest 上设置KeepAlive 属性,瞧,您会在捕获异常时得到响应。 所以工作代码如下所示:

                try
                {
                    var httpRequest = WebRequest.CreateHttp(Protocol + ServerUrl + ":" + ServerPort + ServerAppName + url);
    
                    if (HttpWebRequest.DefaultMaximumErrorResponseLength < int.MaxValue)
                        HttpWebRequest.DefaultMaximumErrorResponseLength = int.MaxValue;
    
                    httpRequest.ContentType = "application/json";
                    httpRequest.Method = method;
                    var encoding = Encoding.GetEncoding("utf-8");
    
                    if (httpRequest.ServicePoint != null)
                    {
                        httpRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
                        httpRequest.ServicePoint.MaxIdleTime = 5000;
                    }
                    //----HERE--
                    httpRequest.KeepAlive = true;
                    //----------
                    using (var response = await httpRequest.GetResponseAsync(token))
                    {
                        using (var reader = new StreamReader(response.GetResponseStream(), encoding))
                        {                       
                            return await reader.ReadToEndAsync();
                        }
                    }
                }
                catch (WebException ex)
                {
                    if (ex.Status == WebExceptionStatus.ProtocolError)
                    {
                        using (var response = (HttpWebResponse)ex.Response)
                        {
                            using (var stream = response.GetResponseStream())
                            {
                                using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                                {
                                    return reader.ReadToEnd();
                                    //or handle it like you want
                                }
                            }
                        }
                    }
                }
    

    我不知道这样保持所有连接是否有效,但由于它帮助我读取来自服务器的实际响应,我认为它可能会帮助遇到同样问题的人。

    编辑:同样重要的是不要与HttpWebRequest.DefaultMaximumErrorResponseLength 混淆。

    【讨论】:

      【解决方案2】:

      我记得之前遇到过类似的问题,并且与设置流的位置有关。 Here is one of my solutions 阅读之前对我有用的 webResponse。请尝试类似的方法是否适合您:-

      private ResourceResponse readWebResponse(HttpWebRequest webreq)
          {
              HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
              HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
              var memStream = new MemoryStream();
              Stream webStream;
                  try
                  {
                      webresp = (HttpWebResponse)webreq.GetResponse();
                      webStream = webresp.GetResponseStream();
                      byte[] readBuffer = new byte[4096];
                      int bytesRead;
                      while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                          memStream.Write(readBuffer, 0, bytesRead);
                  }
                  catch (WebException e)
                  {
                      var r = e.Response as HttpWebResponse;
                      webStream = r.GetResponseStream();
                      memStream = Read(webStream);
                      var wrongLength = memStream.Length;
                  }
      
      
                  memStream.Position = 0;
                  StreamReader sr = new StreamReader(memStream);
                  string webStreamContent = sr.ReadToEnd();
      
                  byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
      //......
      //.......
      

      希望这会有所帮助!

      【讨论】:

      • 感谢您的尝试,但没有帮助。我已经重写了所有内容,使用您的代码进行同步调用(我考虑过流在不同线程中的工作很奇怪)但仍然没有:在 HTTP-400 上 e.Response.ContentLength184webStream.Length0跨度>
      猜你喜欢
      • 2012-06-08
      • 2019-04-04
      • 2016-04-10
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多