来自 HttpWebRequest 生存期范围的响应流

本文关键字:响应 范围 HttpWebRequest 生存期 来自 | 更新日期: 2023-09-27 18:33:19

我有这个方法:

public Stream Load(string term)
{
    var url = CreateSearchUrl(term);
    var webRequest = (HttpWebRequest)WebRequest.Create(url);
    var webResponse = webRequest.GetResponse();
    return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
}

如您所见,我将流返回给调用方,但我不确定这是否安全,因为运行时会释放 WebRequest 并因此使我返回的流无效。

我可以将其转换为字节数组并返回 MemoryStream 甚至使用 WebClient,但我只是不喜欢这个想法 =(。

谢谢!

来自 HttpWebRequest 生存期范围的响应流

没有

一种简单的方法可以在没有资源泄漏的情况下安全地返回 Stream。 主要问题是处理 WebResponse:

public Stream Load(string term)
{
    var url = CreateSearchUrl(term);
    var webRequest = (HttpWebRequest)WebRequest.Create(url);
    var webResponse = webRequest.GetResponse(); // whoops this doesn't get disposed!
    return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
}
关闭 Web 响应实际上比关闭响应流

更重要,因为关闭 WebResponse 会隐式关闭响应流。

据我所知,让WebResponse与Stream一起处置的唯一方法是围绕GZipStream实现一个装饰器,该装饰器在处置WebResponse(以及GZipStream(时处理它。 虽然这可以工作,但它是相当多的代码:

class WebResponseDisposingStream : Stream
{
    private readonly WebResponse response;
    private readonly Stream stream;
    public WebResponseDisposingStream(WebResponse response, Stream stream)
    {
        if (response == null)
            throw new ArgumentNullException("response");
        if (stream == null)
            throw new ArgumentNullException("stream");
        this.response = response;
        this.stream = stream;
    }
    public override void Close()
    {
        this.response.Close();
        this.stream.Close();
    }
    // override all the methods on stream and delegate the call to this.stream
    public override void Flush() { this.stream.Flush(); } // example delegation for Flush()
    // ... on and on for all the other members of Stream
}

也许更好的方法是延续传递样式,其中使用 Stream 的代码作为委托传入:

public void Load(string term, Action<Stream> action)
{
    var url = CreateSearchUrl(term);
    var webRequest = (HttpWebRequest)WebRequest.Create(url);
    using (var webResponse = webRequest.GetResponse())
    using (var responseStream = webResponse.GetResponseStream())
    using (var gzipStream = new GZipStream(responseStream, CompressionMode.Decompress))
    {
        action(gzipStream);
    }
}

现在,调用方只需传入应该对流执行的操作。 在下面,长度将打印到控制台:

Load("test", stream => Console.WriteLine("Length=={0}", stream.Length));

最后一点:如果您不知道,HTTP内置了对压缩的支持。 有关更多详细信息,请参阅维基百科。 HttpWebRequest 通过 AutomaticDecompression 属性内置了对 HTTP 压缩的支持。 使用 HTTP 压缩基本上使压缩对代码透明,并且与 HTTP 工具(浏览器、小提琴手等(配合使用效果更好。