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


Answers

IIS 구성에 액세스 할 수있는 경우

헤더를 적용하고 gzip으로 처리되기를 바랄뿐입니다. 응답은 압축되지 않습니다.

추가 한 헤더를 제거하고 IIS 서버에서 동적 압축 및 정적 콘텐츠 압축을 사용하도록 설정해야합니다.

한 주석 작성자가 stakoverflow에서 다음을 수행하는 방법을 보여주는 좋은 리소스 링크를 언급했습니다.

IIS7 gzip 사용

동적 압축이 이미 설치된 경우 (IIS의 기본 설치가 아님) web.config의 값 설정 만 작동합니다.

이 정보는 MSDN 설명서에서 찾을 수 있습니다. http://www.iis.net/configreference/system.webserver/httpcompression

간단한 압축

다음은 비주얼 스튜디오 프로젝트 템플릿의 Web Api MVC 4 프로젝트를 사용하는 간단한 압축 예제입니다. HttpResponseMessages에 대한 압축을 작동 시키려면 커스텀 MessageHandler를 구현해야한다. 아래의 작업 예제를 참조하십시오.

아래의 코드 구현을 참조하십시오.

당신의 예제와 같은 방식으로 작업을 계속하려고 노력했습니다.

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.Controllers
{
    public class ValuesController : ApiController
    {
        public class Person
        {
            public string name { get; set; }
        }
        // GET api/values
        public IEnumerable<string> Get()
        {
            HttpContext.Current.Response.Cache.VaryByHeaders["accept-encoding"] = true;

            return new [] { "value1", "value2" };
        }

        // GET api/values/5
        public HttpResponseMessage Get(int id)
        {
            HttpContext.Current.Response.Cache.VaryByHeaders["accept-encoding"] = true;

            var TheHTTPResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK); 
            TheHTTPResponse.Content = new StringContent("{\"asdasdasdsadsad\": 123123123 }", Encoding.UTF8, "text/json"); 

            return TheHTTPResponse;
        }

        public class EncodingDelegateHandler : DelegatingHandler
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
                {
                    HttpResponseMessage response = responseToCompleteTask.Result;

                    if (response.RequestMessage.Headers.AcceptEncoding != null &&
                        response.RequestMessage.Headers.AcceptEncoding.Count > 0)
                    {
                        string encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value;

                        response.Content = new CompressedContent(response.Content, encodingType);
                    }

                    return response;
                },
                TaskContinuationOptions.OnlyOnRanToCompletion);
            }
        }

        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();
                    }
                });
            }
        }
    }
}

또한 새 메시지 핸들러를 앱 구성에 추가하십시오.

using System.Web.Http;
using MvcApplication1.Controllers;

namespace MvcApplication1
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.MessageHandlers.Add(new ValuesController.EncodingDelegateHandler());

            config.EnableSystemDiagnosticsTracing();
        }
    }
}

사용자 지정 처리기는 - Kiran Challa ( http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx )

인바운드 스트림의 수축을 구현하는 더 좋은 예가 있습니다. 아래 예도 볼 수 있습니다.

또한이 모든 것을 github에서 지원하는 정말 멋진 프로젝트를 발견했습니다.

이 대답에 나 자신이 도착했다는 사실에 주목하십시오. 귀하의 의견에 Simon이 (가)이 답변 날짜로부터이 접근법을 2 일 전에 제안했습니다.

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 압축




다음 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




applicationHost.config 파일을 통해 IIS에서 압축을 사용하기위한 부록입니다.

IIS 구성 관리자 를 사용하여 변경하거나 notepad.exe 를 사용하여 파일을 편집하십시오. Notepad++ 하고 있었고 파일이 저장 중이었지만 실제로는 저장되지 않았습니다.

32/64 비트 환경, config 및이를 편집하는 프로그램과 관련이 있습니다. 내 오후를 망 쳤어 !!