我可以将压缩的GZipStream复制到另一个流吗?

时间:2018-07-30 11:03:58

标签: c# asp.net-core stream compression

我正在使用ASP.NET Core 2.0为某些站点编写代理。如果代理仅将HttpResponseMessage重新转换为浏览器,则代理工作正常。我基于this示例的代理。但是我需要对网站内容进行一些更改,例如,某些href包含一个绝对引用。因此,当我从代理中单击它们时,便会到达原始站点,这是一个问题。

我使用发现here的方式访问目标页面内容。但是,当我尝试将更改的内容复制到HttpResponse.Body时,遇到NotSupportedException消息GZipStream does not support reading。我的代码在下面:

public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
{
    if (responseMessage == null)
    {
        throw new ArgumentNullException(nameof(responseMessage));
    }

    var response = context.Response;
    response.StatusCode = (int)responseMessage.StatusCode;

    //work with headers

    using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
    {
        string str;
        using (var gZipStream = new GZipStream(responseStream, CompressionMode.Decompress))
        using (var streamReader = new StreamReader(gZipStream))
        {
            str = await streamReader.ReadToEndAsync();
            //some stings changes...
        }
        var bytes = Encoding.UTF8.GetBytes(str);
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gZipStream = new GZipStream(mso, CompressionMode.Compress))
            {
                await msi.CopyToAsync(gZipStream);
                await gZipStream.CopyToAsync(response.Body, StreamCopyBufferSize, context.RequestAborted);
            }
        }
        //next string works, but I don't change content this way
        //await responseStream.CopyToAsync(response.Body, StreamCopyBufferSize, context.RequestAborted);
    }
}

经过一番搜索,我发现压缩到GZipStream gZipStream.CanRead是假的之后,如果CompressionModeCompressed似乎总是假的。我还尝试将msi复制到response.Body中,它不会引发异常,但是在浏览器中我得到一个空白页(浏览器控制台中“网络中的文档响应”也是空白)。

是否可以将压缩的GZipStream复制到另一个Stream上,或者我的方式是完全错误的?

1 个答案:

答案 0 :(得分:1)

GZipStream不能直接从其复制。您的mso Stream正在保存压缩数据。

但是您可以完全删除mso流并将其从msi流复制到响应中。正文:

using (var msi = new MemoryStream(bytes))
{
    using (var gZipStream = new GZipStream(response.Body, CompressionMode.Compress)) //<-- declare your response.Body as the target for the compressed data 
    {
        await msi.CopyToAsync(gZipStream, StreamCopyBufferSize, context.RequestAborted); //copy the msi stream to the response.Body through the gZipStream
    }
}