asp.net webservice处理gzip压缩请求

时间:2010-12-07 13:30:27

标签: asp.net web-services iis-7 asmx gzip

我有一个asp.net .asmx webservice,用于处理来自第三方工具的请求。第三方工具向Web服务发出http POST请求以获取用户信息。我正在使用IIS7

选中“删除所有编码”运行Fiddler,我可以看到webservice调用,并且一切正常。如果取消选中“删除所有编码”,则Web服务调用将失败并显示400 Bad Request。我看到的区别是Fiddler正在删除标题“Content-Encoding:gzip”,内容正在解压缩。

因此,当删除Content-Encoding标头并解压缩内容时,我的webservice功能完美。当标题存在且内容被压缩时,Web服务将失败。

我怎么能:

  1. 配置我的webservice告诉客户端它不接受压缩请求(并希望第三方工具尊重它)
  2. 在asp.net处理早期解压缩内容
  3. 修改我的网络服务以使用压缩数据
  4. 更新:为了清楚起见,我不需要在Response中配置gzip编码,我需要处理一个请求到我的gzip编码的web服务。

    更新2 :第三方工具是Salesforce.com Outlook插件。因此,我无权修改它,许多其他公司也毫无困难地使用它。它必须是我正在做的事情(或不做)

    更新3 :我发现一个帖子here表示IIS不支持带压缩数据的传入POST请求,它只支持压缩响应。这仍然可以吗?

5 个答案:

答案 0 :(得分:5)

最简单的方法是创建一个替换请求过滤器的HttpModule。它更可重用,并避免使用Global.asax。由于GZipStream已为此做好准备,因此无需创建新的解压缩流类。以下是完整代码,它还删除了不再需要的Content-Encoding: gzip

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>

答案 1 :(得分:2)

由于第三方服务只是向您发送POST,我认为不可能告诉他们不要发送压缩文件。

您可以尝试覆盖GetWebRequest并在

中的路上解压缩
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol

{
protected override WebRequest GetWebRequest(Uri uri)
{
    base.GetWebRequest(uri);request.AutomaticDecompression = System.Net.DecompressionMethods.GZip;
    return request;
}
}

答案 2 :(得分:1)

GZIP压缩是服务器的功能。

如果您使用的是IIS6,请咨询this link

如果您使用的是IIS7,则可以使用ISAPI_Rewrite来禁用gzip。请参阅this link

也就是说,因为gzip是IIS的一个功能,所以你真的不应该做任何“特殊”的事情来让它与Web服务一起工作(IIS应该处理解压缩和压缩请求)。希望这些信息可以帮助您进一步解决问题并解决问题。

答案 3 :(得分:1)

我不确定IIS是否支持解压缩传入的请求,因此可能需要在管道中进一步完成。

设拉子的答案具有工作的潜力,这将是我尝试的第一件事。

如果这不起作用,您可以考虑将服务器.asmx服务切换到WCF,虽然设置它有点困难,但也提供了更大的灵活性。

在WCF方面,我可以提出两件事。第一个很容易实现,它基于设置WCF使用的WebRequest对象自动接受压缩。您可以找到详细信息here。这个是WCF,相当于Shiraz提出的解决方案。

第二个更复杂,因为它涉及创建自定义消息编码器,但如果上述方法都不起作用,这应该可以解决问题。描述了创建消息压缩编码器here。您可能还想查看here中的答案,该答案显示了邮件编码器的示例配置。

如果有帮助或需要更多帮助,请告诉我。

答案 4 :(得分:1)

我找到了部分答案here

class DecompressStream : Stream
{
    ...

    public override int Read(byte[] buffer, int offset, int count)
    {
        GZipStream test = new GZipStream(_sink, CompressionMode.Decompress);

        int c = test.Read(buffer, offset, count);

        return c;
    }

    ...
}

然后,我可以在请求对象上指定过滤器,如下所示:

void Application_BeginRequest(object sender, EventArgs e)
    {
        string contentEncoding = Request.Headers["Content-Encoding"];
        Stream prevCompressedStream = Request.Filter;

        if(contentEncoding == null || contentEncoding.Length == 0)
            return;

        contentEncoding = contentEncoding.ToLower();

        if(contentEncoding.Contains("gzip"))
        {
            Request.Filter = new DecompressStream(Request.Filter);
        }
    }

我说部分答案,因为即使我现在可以处理传入的请求,但即使响应未编码,响应也会获得“Content-Encoding:gzip”标头。我可以在Fiddler中验证内容是否未编码。

如果我对响应进行编码,则Web服务的客户端将失败。似乎即使它发送“Accept-Encoding:gzip”,它实际上也不接受gzip压缩响应。我可以在Fiddler中验证响应是否被压缩,Fiddler将成功解压缩。

所以,现在我一直试图从响应中删除一个流浪的“Content-Encoding:gzip”标头。我已从应用程序,web.config和IIS中删除了我可以找到的所有引用。