【问题标题】:How do I enable GZIP compression for POST (upload) requests to a SOAP WebService on IIS 7?如何为 IIS 7 上的 SOAP WebService 的 POST(上传)请求启用 GZIP 压缩?
【发布时间】:2013-05-16 07:00:09
【问题描述】:

如何为上传到 .NET WebService(SOAP,而不是 WCF)的 POST 数据启用压缩?我认为这将是 IIS 中的 enabling dynamic compression 的简单问题,但启用后,它只是压缩 响应,而不是 POST 请求

我已将其添加为服务参考,但在生成的 SOAPClient 上找不到任何设置来启用请求压缩。

似乎我可能缺少客户端的配置设置或代码来压缩请求,然后再将其发送到服务器?还是我正在尝试做的事情(GZipping POST 数据)甚至不受支持?

更多信息:我在客户端和服务器上使用 .NET 4.0。

【问题讨论】:

标签: asp.net web-services iis-7 http-compression


【解决方案1】:

我在 4 年前写过博客

http://netpl.blogspot.com/2009/07/aspnet-webservices-two-way-response-and.html

我想知道为什么你没有通过谷歌搜索找到这个。无论如何,这应该适合你,我们已经在生产环境中工作了 4 年。

【讨论】:

  • 实际上我已经在使用该代码,但它有几个我很难修复的错误。但是我在这方面花了更多时间,现在已经修复了这些错误。我的版本修复了以下问题: 在服务器发生异常时设置内容编码 gzip 标头。第二个修复:当请求未经过 GZIP 压缩时,不要尝试解密 GZIP 请求流。我在这里发布了代码的更新版本:pastebin.com/Aak9FUiw
  • 非常感谢原始解决方案。我会奖励你赏金:)
  • 第三个修复是抑制“内容编码”标头的加倍,使其变为“gzip,gzip”。不确定这是否真的有必要,但它不正确。
  • 谢谢尼克,我希望该解决方案能像对我们一样为您服务。
  • 我现在实际上不得不删除此代码。即使是“固定”版本也有一些我不知道如何解决的问题。例如,如果 Web 服务超时,您会收到“对象未设置为对象实例”的错误(隐藏了真正的错误)。
【解决方案2】:

最后,我使用了 Wiktor Zychla 的答案,但遇到了几个错误(也在他文章的 cmets 中提到)。为了完整起见,我将在此处发布我的 HttpCompression 模块的固定版本,但您需要的其余代码(和实施指南)位于 Wiktor's article

更新:

我实际上不得不停止使用此代码,因为它有一个我无法修复的错误(即使使用下面的改进版本)。对于代理服务器背后的许多人来说,它会出现一个错误,上面写着“gzip 标头中的幻数不正确”,我不知道如何解决这个问题。我认为这是因为代理服务器解压缩 GZIP 并且此代码不允许以当前形式接收压缩和非压缩响应。

using System;
using System.IO.Compression;
using System.Web;
using System.Web.Security;

/// <summary>
/// Implement two way HTTP compression for the SOAP API
/// Code taken from: http://netpl.blogspot.co.uk/2009/07/aspnet-webservices-two-way-    response-and.html
/// Fix: Set Content-encoding: gzip header when an Exception occurs on the server.
/// Fix: Do not attempt to decrypt GZIP request stream when request was not GZIPed.
/// </summary>
public class HttpCompressionModule : IHttpModule
{
    private bool isDisposed = false;

    ~HttpCompressionModule()
    {
            Dispose(false);
    }

    public void Init(HttpApplication context)
    {
            context.BeginRequest += new EventHandler(Context_BeginRequest);
            context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders);
    }

    void context_PreSendRequestHeaders(object sender, EventArgs e)
    {
            // Fix headers having been lost if an exception occurred.
            HttpApplication app = sender as HttpApplication;
            HttpContext ctx = app.Context;
            if (app.Response.Filter is GZipStream) SetEncoding("gzip");
            else if (app.Response.Filter is DeflateStream) SetEncoding("deflate");

            // Fix double header
            if (ctx.Response.Headers["Content-encoding"] == "gzip,gzip")
                    ctx.Response.Headers.Set("Content-encoding", "gzip");
    }

    public void Context_BeginRequest(object sender, EventArgs e)
    {
            HttpApplication app = sender as HttpApplication;
            HttpContext ctx = app.Context;

            // Currently only enable for the Uploader API webservice
            if (!ctx.Request.Url.PathAndQuery.ToLower().Contains("uploaderapi.asmx"))
            {
                    return;
            }

            // Add request filter if request was GZIP encoded
            string requestEncoding = ctx.Request.Headers["Content-encoding"];
            if (requestEncoding != null && requestEncoding == "gzip")
            {
               app.Request.Filter =
                    new System.IO.Compression.GZipStream(app.Request.Filter, CompressionMode.Decompress);
            }

            // Add response compression filter if the client accepts compressed responses
            if (IsEncodingAccepted("gzip"))
            {
                    app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);
                    SetEncoding("gzip");
            }
            else if (IsEncodingAccepted("deflate"))
            {
                    app.Response.Filter = new DeflateStream(app.Response.Filter, CompressionMode.Compress);
                    SetEncoding("deflate");
            }
    }

    private bool IsEncodingAccepted(string encoding)
    {
            return HttpContext.Current.Request.Headers["Accept-encoding"] != null &&
                    HttpContext.Current.Request.Headers["Accept-encoding"].Contains(encoding);
    }

    private void SetEncoding(string encoding)
    {
            HttpContext ctx = HttpContext.Current;
            string responseEncodings = ctx.Response.Headers.Get("Content-encoding");
            if (responseEncodings == null || !responseEncodings.Contains(encoding))
                    HttpContext.Current.Response.AppendHeader("Content-encoding", encoding);
    }

    public void Dispose()
    {
            Dispose(true);
    }

    private void Dispose(bool dispose)
    {
            isDisposed = dispose;
    }
}

【讨论】:

  • 尼克,请记住,这不是一个完整的答案。 HttpResponseDecompressed 和 HttpRequestCompressed 也是必需的。
  • @WiktorZychla 谢谢 - 我已经更新了我的答案,以明确您的文章包含所有代码/说明。我的回答只是修复我发现的那些错误/兼容性问题(如果您决定将它们合并到您的文章中,这将是多余的)。
  • 尼克,因为你的解释清楚,我不打算对条目做任何修改。我假设任何尝试使用它的人都会找到您的 cmets 并遵循您更新的方法。很高兴该解决方案有所帮助,并感谢您的修复。
猜你喜欢
  • 2011-05-21
  • 2017-05-01
  • 1970-01-01
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-20
  • 1970-01-01
相关资源
最近更新 更多