繁体   English   中英

使用ServiceStack支持压缩请求体

[英]Supporting compressed request body with ServiceStack

我需要实现可以接受POST消息与gzip压缩请求主体 (未, 压缩的响应主体)的端点。

我发现了一种通过标记与请求DTO来处理这很容易地IRequiresRequestStream ,并使用GZipStream服务类解压缩的原始请求主体,构建代表解压缩数据的字符串。 它是一个纯文本请求体,因此在这种情况下,跳过自动请求DTO反序列化没有任何损失。

这很好,我可以在那里停止,但我在考虑是否可以用通用方式编写它,以便如果正确设置了Content-Encoding标头,那么发布到ServiceStack的每个请求都可以解压缩。 我编写了一个看起来非常好的PreRequestFilter ,直到遇到问题:我找不到修改原始请求输入流的方法,或者确保管道中的反序列化和其他代码可以访问解压缩的字节而不是压缩数据:

public static void Decompress(IRequest request, IResponse response)
{
    if (!request.Headers[HttpHeaders.ContentEncoding].EqualsIgnoreCase(CompressionTypes.GZip))
        return;

    request.UseBufferedStream = true;
    using (var decompressor = new GZipStream(request.InputStream, CompressionMode.Decompress))
    {
        var decompressedBytes = decompressor.ReadFully();

        // Fails because the MemoryStream, used when UseBufferedStream
        // is true, is not expandable.
        // Or, if we set request.UseBufferedStream = false first, then 
        // it fails because the original HttpInputStream is not writeable.
        request.InputStream.SetLength(decompressedBytes.Length);
        request.InputStream.Write(decompressedBytes, 0, decompressedBytes.Length);
   }
}
PreRequestFilters.Add(Decompress);

有没有办法在PreRequestFilter或RawHttpHandler中修改请求体? 或者,是否有一种完全不同的方式来实现任何内容类型/ DTO的通用请求体解压缩? 我现在工作的每请求实现很好,但找到一般解决方案会很有趣。

您可以覆盖AppHost.OnPreExecuteServiceFilter()以更改用于执行服务的Request DTO,例如:

class AppHost : AppHostBase
{
    public virtual object OnPreExecuteServiceFilter(IService service,
        object request, IRequest httpReq, IResponse httpRes)
    {
        if (httpReq.Headers[HttpHeaders.ContentEncoding]
            .EqualsIgnoreCase(CompressionTypes.GZip))
        {
            //...
            return customRequest;
        }

        return request;
    }
}

使用通用ASP.NET HTTP模块

由于这可以在外部HTTP协议层进行通用化,因此更好的选择是使用泛型GZip HttpModule ,例如:

public class GZipRequestDecompressingModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, e) =>
        {
            var request = (sender as HttpApplication).Request;

            string contentEncoding = request.Headers["Content-Encoding"];

            if (string.Equals(contentEncoding, "gzip",
                StringComparison.OrdinalIgnoreCase))
            {
                request.Filter = new GZipStream(request.Filter,
                    CompressionMode.Decompress);
                request.Headers.Remove("Content-Encoding");
            }
        };
    }
    public void Dispose()
    {
    }
}

可以在Web.Config中配置:

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="AnyUniqueName"
            type="YourNamespace.GZipRequestDecompressingModule, YourAssembly"
            preCondition="integratedMode" />
    </modules>
</system.webServer>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM