Как включить сжатие GZIP для запросов POST (загрузки) на веб-службу SOAP на IIS 7?
Как включить сжатие для POST-данных, загружаемых в.NET WebService (SOAP, а не WCF)? Я думал, что будет просто включить динамическое сжатие в IIS, но после включения он сжимает только ответ, а не запрос POST.
Я добавил его в качестве справочника услуг и не могу найти какие-либо настройки в сгенерированном SOAPClient для включения сжатия запросов.
Возможно, мне не хватает параметра конфигурации или кода на стороне клиента для сжатия запроса перед его отправкой на сервер? Или то, что я пытаюсь сделать (данные GZipping POST), даже не поддерживается?
Дополнительная информация: я использую.NET 4.0 на клиенте и сервере.
2 ответа
Я писал об этом 4 года назад
http://netpl.blogspot.com/2009/07/aspnet-webservices-two-way-response-and.html
Интересно, почему вы не нашли это, погуглив. В любом случае, это должно работать для вас, у нас это работает в производственной среде уже 4 года.
В конце концов, я воспользовался ответом Виктора Зихлы, но натолкнулся на пару ошибок (также упомянутых в комментариях к его статье). Для полноты я опубликую здесь свою исправленную версию модуля HttpCompression, но остальная часть кода (и рекомендации по реализации), которые вам нужны, находятся в статье Wiktor.
ОБНОВИТЬ:
На самом деле мне пришлось прекратить использовать этот код, так как в нем есть ошибка, которую я не могу исправить (даже с моей улучшенной версией ниже). Для многих людей, работающих за прокси-серверами, возникает ошибка, которая гласит: "магическое число в заголовке 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;
}
}