Skip to main content
 首页 » 编程设计

c#之无法从 WebException 获取 ResponseStream

2024年08月06日37mayingbao

我有一个桌面客户端,它通过 Http 与服务器端通信。 当服务器在数据处理方面出现一些问题时,它会在具有正确的 Http 代码(主要是 HTTP-400)的 Http 响应正文中返回 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(它是 "") 我什至不知道去哪里看,因为一切看起来都应该有效。

可能是什么问题?

请您参考如下方法:

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

问题是 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。