无法从 WebException 获取 ResponseStream

mai*_*ray 2 .net c# httpwebresponse system.net.webexception

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

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

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

但是当发生错误并且 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();
                            }
                        }
                    }
                }
            }
Run Code Online (Sandbox Code Playgroud)

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

可能是什么问题?

mai*_*ray 6

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

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

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

            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
                            }
                        }
                    }
                }
            }
Run Code Online (Sandbox Code Playgroud)

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

编辑:同样重要的是不要弄乱HttpWebRequest.DefaultMaximumErrorResponseLength.