[c#] HttpResponseMessage 반환시 ​​WebAPI Gzip



Answers

다음 NuGet 패키지를 추가하십시오.

Microsoft.AspNet.WebApi.Extensions.Compression.Server System.Net.Http.Extensions.Compression.Client

그런 다음 App_Start\WebApiConfig.cs 에 한 줄의 코드를 추가하십시오.

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

그 트릭을 할 것입니다!

세부 정보 :

희망이 도움이됩니다.

** @JCisar의 의견 이후에 업데이트 됨

ASP.Net 핵심에 대한 업데이트

누젠 패키지

Microsoft.AspNetCore.ResponseCompression

Question

HttpResponseMessage 를 반환하는 WebAPI 컨트롤러가 있고 gzip 압축을 추가하려고합니다. 다음은 서버 코드입니다.

using System.Net.Http;
using System.Web.Http;
using System.Web;
using System.IO.Compression;

[Route("SomeRoute")]
public HttpResponseMessage Post([FromBody] string value)
{
    HttpContext context = HttpContext.Current;

    context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);

    HttpContext.Current.Response.AppendHeader("Content-encoding", "gzip");
    HttpContext.Current.Response.Cache.VaryByHeaders["Accept-encoding"] = true;

    return new SomeClass().SomeRequest(value);
}

그리고 이것은 jquery를 사용하여 ajax 호출을위한 클라이언트 코드입니다.

$.ajax({
    url: "/SomeRoute",
    type: "POST",
    cache: "false",
    data: SomeData,
    beforeSend: function (jqXHR) { jqXHR.setRequestHeader('Accept-Encoding', 'gzip'); },
    success: function(msg) { ... }

이 코드를 실행하면 서버 코드가 도청되지 않고 클라이언트 버그로 반환됩니다.

(failed)
net::ERR_CONTENT_DECODING_FAILED

내가 Fiddler를 볼 때, 이것은 내가 보는 것입니다.

웹 서비스가 클라이언트가 정상적으로 처리하는 gzip으로 처리 된 콘텐츠를 반환하도록 변경하려면 어떻게해야합니까? 나는 또한 HttpModule 또는 IIS의 일부 설정을 통해이 작업을 수행 할 수 있음을 알고 있지만 어느 옵션도 호스팅의 시나리오에 맞지 않습니다.

내가 (호스팅)에 대한 액세스 권한이 없기 때문에 IIS 설정을 찾고 있지 않습니다.




IIS 설정이나 Nuget 패키지 설치 편집하지 않고 한 가지 해결책은 WEB API에 MessageHandler 를 추가하는 것입니다.

이렇게하면 "AcceptEncoding"헤더로 요청을 catch하고 System.IO.Compression 라이브러리의 Build를 사용하여 압축합니다.

public class CompressHandler : DelegatingHandler
{
    private static CompressHandler _handler;
    private CompressHandler(){}
    public static CompressHandler GetSingleton()
    {
        if (_handler == null)
            _handler = new CompressHandler();
        return _handler;
    }
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
        {
            HttpResponseMessage response = responseToCompleteTask.Result;
            var acceptedEncoding =GetAcceptedEncoding(response);
            if(acceptedEncoding!=null)
                response.Content = new CompressedContent(response.Content, acceptedEncoding);

            return response;
        },
        TaskContinuationOptions.OnlyOnRanToCompletion);
    }
    private string GetAcceptedEncoding(HttpResponseMessage response)
    {
        string encodingType=null;
        if (response.RequestMessage.Headers.AcceptEncoding != null && response.RequestMessage.Headers.AcceptEncoding.Any())
        {
            encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value;
        }
        return encodingType;
    }


}

    public class CompressedContent : HttpContent
{
    private HttpContent originalContent;
    private string encodingType;

    public CompressedContent(HttpContent content, string encodingType)
    {
        if (content == null)
        {
            throw new ArgumentNullException("content");
        }

        if (encodingType == null)
        {
            throw new ArgumentNullException("encodingType");
        }

        originalContent = content;
        this.encodingType = encodingType.ToLowerInvariant();

        if (this.encodingType != "gzip" && this.encodingType != "deflate")
        {
            throw new InvalidOperationException(string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", this.encodingType));
        }

        // copy the headers from the original content
        foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
        {
            this.Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        this.Headers.ContentEncoding.Add(encodingType);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = -1;

        return false;
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        Stream compressedStream = null;

        if (encodingType == "gzip")
        {
            compressedStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true);
        }
        else if (encodingType == "deflate")
        {
            compressedStream = new DeflateStream(stream, CompressionMode.Compress, leaveOpen: true);
        }

        return originalContent.CopyToAsync(compressedStream).ContinueWith(tsk =>
        {
            if (compressedStream != null)
            {
                compressedStream.Dispose();
            }
        });
    }
}

그리고이 핸들러를 Global.asax.cs에 추가하십시오.

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, CompressHandler.GetSingleton());

벤 포스터의 명성. ASP.NET 웹 API 압축




Related