ASP.NET Core의 응답 압축

네트워크 대역폭은 제한된 리소스입니다. 응답 크기를 줄이면 일반적으로 앱의 응답성이 크게 향상됩니다. 페이로드 크기를 줄이는 한 가지 방법은 앱의 응답을 압축하는 것입니다.

HTTPS를 사용하여 압축

보안 연결을 통해 압축된 응답은 보안 위험으로 인해 기본적으로 사용하지 않도록 설정되는 EnableForHttps 옵션을 사용하여 컨트롤할 수 있습니다. 동적으로 생성된 페이지에서 압축을 사용하면 앱을 CRIMEBREACH 공격에 노출할 수 있습니다. 위조 방지 토큰을 사용하여 CRIME 및 BREACH 공격을 ASP.NET Core에서 완화할 수 있습니다. 자세한 내용은 ASP.NET Core에서 교차 사이트 요청 위조(XSRF/CSRF) 공격 방지를 참조하세요. BREACH 공격 완화에 대한 자세한 내용은 http://www.breachattack.com/완화를 참조하세요.

앱에서 EnableForHttps를 사용하지 않도록 설정한 경우에도 IIS, IIS Express 및 Azure App Service는 IIS 웹 서버에서 gzip을 적용할 수 있습니다. 응답 헤더를 검토할 때 서버 값을 기록해 둡니다. 예기치 않은 content-encoding 응답 헤더 값은 ASP.NET Core 앱 구성이 아닌 웹 서버의 결과일 수 있습니다.

응답 압축 미들웨어를 사용하는 경우

IIS, Apache 또는 Nginx에서 서버 기반 응답 압축 기술을 사용합니다. 응답 압축 미들웨어의 성능이 서버 모듈의 성능과 일치하지 않을 수 있습니다. HTTP.sys 서버 및 Kestrel 서버는 현재 기본 제공 압축 지원을 제공하지 않습니다.

앱이 다음과 같은 경우 응답 압축 미들웨어를 사용합니다.

응답 압축

일반적으로 기본적으로 압축되지 않은 모든 응답은 응답 압축의 이점을 누릴 수 있습니다. 원시적으로 압축되지 않은 응답에는 일반적으로 CSS, JavaScript, HTML, XML 및 JSON이 포함됩니다. PNG 파일과 같이 원시적으로 압축된 자산은 압축하면 안 됩니다. 원시적으로 압축된 응답을 추가로 압축하려는 경우 압축을 처리하는 데 걸린 시간 때문에 크기 및 전송 시간이 약간 더 감소한 것이 느껴지지 않을 수 있습니다. 파일의 내용과 압축 효율성에 따라 약 150-1000바이트보다 작은 파일은 압축하지 않도록 합니다. 작은 파일을 압축하는 오버헤드로 인해 압축되지 않은 파일보다 큰 압축된 파일이 생성될 수 있습니다.

클라이언트가 압축된 콘텐츠를 처리할 수 있는 경우 클라이언트는 요청과 함께 Accept-Encoding 헤더를 전송하여 해당 기능을 서버에 알려야 합니다. 서버는 압축된 콘텐츠를 보낼 때 압축된 응답의 인코딩 방법에 대한 정보를 Content-Encoding 헤더에 포함해야 합니다. 응답 압축 미들웨어에서 지원하는 콘텐츠 인코딩 지정은 다음 표에 나와 있습니다.

Accept-Encoding 헤더 값 지원되는 미들웨어 설명
br 예(기본값) Brotli 압축 데이터 형식
deflate 아니요 DEFLATE 압축 데이터 형식
exi 아니요 W3C Efficient XML Interchange
gzip Gzip 파일 형식
identity “인코딩 안 함” 식별자: 응답을 인코딩하지 않아야 합니다.
pack200-gzip 아니요 Java 보관을 위한 네트워크 전송 형식
* 명시적으로 요청되지 않은 사용 가능한 모든 콘텐츠 인코딩

자세한 내용은 IANA 공식 콘텐츠 코딩 목록을 참조하세요.

응답 압축 미들웨어를 사용하면 사용자 지정 Accept-Encoding 헤더 값에 대한 추가 압축 공급자를 추가할 수 있습니다. 자세한 내용은 이 문서의 사용자 지정 공급자를 참조하세요.

응답 압축 미들웨어는 압축 스키마의 우선 순위를 지정하기 위해 클라이언트에서 보낼 때 품질 값(qvalue, q) 가중치에 반응할 수 있습니다. 자세한 내용은 RFC 9110: Accept-Encoding을 참조하세요.

압축 알고리즘은 압축 속도와 압축의 효율성 간에 균형을 유지합니다. 이 컨텍스트의 ‘효과’는 압축 후 출력의 크기를 나타냅니다. 최적 압축을 통해 가장 작은 크기를 달성합니다.

다음 표에서는 압축된 콘텐츠를 요청, 송신, 캐싱 및 수신하는 것과 관련된 헤더에 대해 설명합니다.

헤더 역할
Accept-Encoding 클라이언트에서 서버로 전송되어 클라이언트에 허용되는 콘텐츠 인코딩 스키마를 표시합니다.
Content-Encoding 서버에서 클라이언트로 전송되어 페이로드에 있는 콘텐츠의 인코딩을 나타냅니다.
Content-Length 압축이 발생하면 응답이 압축될 때 본문 내용이 변경되므로 Content-Length 헤더가 제거됩니다.
Content-MD5 압축이 발생하면 본문 내용이 변경되고 해시가 더 이상 유효하지 않기 때문에 Content-MD5 헤더가 제거됩니다.
Content-Type 콘텐츠의 MIME 형식을 지정합니다. 모든 응답은 해당 Content-Type을 지정해야 합니다. 응답 압축 미들웨어는 이 값을 확인하여 응답을 압축해야 하는지 여부를 결정합니다. 응답 압축 미들웨어는 인코딩할 수 있는 기본 MIME 형식 집합을 지정하며, 대체되거나 추가될 수 있습니다.
Vary 서버에서 Accept-Encoding 값을 클라이언트 및 프록시로 보내는 경우 Vary 헤더는 요청의 Accept-Encoding 헤더 값을 기준으로 응답을 캐시(다르게 지정)해야 한다는 것을 클라이언트나 프록시에 나타냅니다. Vary: Accept-Encoding 헤더를 사용하여 콘텐츠를 반환하게 되면 압축된 응답과 압축되지 않은 응답이 모두 개별적으로 캐시됩니다.

샘플 앱을 사용하여 응답 압축 미들웨어의 기능을 살펴봅니다. 이 샘플은 다음을 보여 줍니다.

  • Gzip 및 사용자 지정 압축 공급자를 사용하는 앱 응답 압축
  • 압축을 위해 MIME 형식을 MIME 형식 기본 목록에 추가하는 방법입니다.
  • 사용자 지정 응답 압축 공급자를 추가하는 방법입니다.

구성

다음 코드에서는 기본 MIME 형식 및 압축 공급자(Brotli 및 Gzip)에 대해 응답 압축 미들웨어를 사용하도록 설정하는 방법을 보여 줍니다.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
});

var app = builder.Build();

app.UseResponseCompression();

app.MapGet("/", () => "Hello World!");

app.Run();

참고:

  • EnableForHttpstrue로 설정하는 것은 보안상 위험합니다. 자세한 내용은 이 문서의 HTTPS를 사용하여 압축을 참조하세요.
  • app.UseResponseCompression은 응답을 압축하는 미들웨어 전에 호출해야 합니다. 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.
  • Firefox Browser Developer와 같은 도구를 사용하여 요청 헤더를 Accept-Encoding 설정하고 응답 헤더, 크기 및 본문을 검사합니다.

Accept-Encoding 헤더 없이 샘플 앱에 요청을 제출하고 응답이 압축되지 않았는지 확인합니다. Content-Encoding 헤더가 Response Headers 컬렉션에 없습니다.

예를 들어 Firefox Developer에서 다음을 수행합니다.

  • 네트워크 탭을 선택합니다.
  • 네트워크 요청 목록에서 요청을 마우스 오른쪽 버튼으로 클릭하고 편집 및 다시 보내기를 선택합니다.
  • Accept-Encoding:gzip, deflate, br에서 none으로 변경합니다.
  • 보내기를 선택합니다.

개발자 도구를 사용하여 브라우저에서 샘플 앱에 요청을 제출하고 응답이 압축되었는지 확인합니다. Content-EncodingVary 헤더가 응답에 있습니다.

공급자

Brotli 및 Gzip 압축 공급자

BrotliCompressionProvider를 사용하여 Brotli 압축 데이터 형식으로 응답을 압축합니다.

CompressionProviderCollection명시적으로 추가된 압축 공급자가 없는 경우 다음을 수행합니다.

  • Brotli 압축 공급자 및 Gzip 압축 공급자는 기본적으로 압축 공급자 배열에 추가됩니다.
  • 클라이언트에서 Brotli 압축 데이터 형식이 지원되는 경우 기본 압축은 Brotli 압축입니다. 클라이언트에서 Brotli를 지원하지 않고 클라이언트가 Gzip 압축을 지원하면 기본 압축은 Gzip입니다.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

압축 공급자가 추가되면 다른 공급자가 추가되지 않습니다. 예를 들어 Gzip 압축 공급자가 명시적으로 추가된 유일한 공급자인 경우 다른 압축 공급자가 추가되지 않습니다.

코드는 다음과 같습니다.

  • HTTPS 요청에 대한 응답 압축을 사용하도록 설정합니다.
  • Brotli 및 Gzip 응답 압축 공급자를 추가합니다.
using System.IO.Compression;
using Microsoft.AspNetCore.ResponseCompression;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.Fastest;
});

builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.SmallestSize;
});

var app = builder.Build();

app.UseResponseCompression();

app.MapGet("/", () => "Hello World!");

app.Run();

BrotliCompressionProviderOptionsGzipCompressionProviderOptions를 사용하여 압축 수준을 설정합니다. Brotli 및 Gzip 압축 공급자는 가장 빠른 압축 수준인 CompressionLevel.Fastest가 기본값으로 설정되며, 이는 가장 효율적인 압축을 생성하지 못할 수 있습니다. 가장 효율적인 압축이 필요한 경우 최적의 압축을 위해 응답 압축 미들웨어를 구성합니다.

압축 작업에서 속도 또는 압축 크기를 강조하는지 여부를 나타내는 값은 CompressionLevel 열거형을 참조하세요.

using System.IO.Compression;
using Microsoft.AspNetCore.ResponseCompression;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.Fastest;
});

builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.SmallestSize;
});

var app = builder.Build();

app.UseResponseCompression();

app.MapGet("/", () => "Hello World!");

app.Run();

사용자 지정 공급자

ICompressionProvider를 사용하여 사용자 지정 압축 구현을 만듭니다. EncodingNameICompressionProvider가 생성하는 콘텐츠 인코딩을 나타냅니다. 응답 압축 미들웨어는 이 정보를 사용하여 요청의 Accept-Encoding 헤더에 지정된 목록에 따라 공급자를 선택합니다.

헤더가 있는 샘플 앱에 대한 요청은 Accept-Encoding: mycustomcompression 헤더가 있는 응답을 Content-Encoding: mycustomcompression 반환합니다. 사용자 지정 압축 구현이 작동하려면 클라이언트는 사용자 지정 인코딩의 압축을 풀 수 있어야 합니다.

using Microsoft.AspNetCore.ResponseCompression;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
    options.Providers.Add<CustomCompressionProvider>();
});

var app = builder.Build();

app.UseResponseCompression();

app.MapGet("/", () => "Hello World!");

app.Run();
using Microsoft.AspNetCore.ResponseCompression;

public class CustomCompressionProvider : ICompressionProvider
{
    public string EncodingName => "mycustomcompression";
    public bool SupportsFlush => true;

    public Stream CreateStream(Stream outputStream)
    {
        // Replace with a custom compression stream wrapper.
        return outputStream;
    }
}

이전 코드를 사용하면 응답 본문이 샘플에 의해 압축되지 않습니다. 그러나 이 샘플에서는 사용자 지정 압축 알고리즘을 구현할 위치를 보여 줍니다.

MIME 형식

응답 압축 미들웨어는 압축을 위한 기본 MIME 형식의 집합을 지정합니다. 지원되는 MIME 형식의 전체 목록에 대한 소스 코드를 참조하세요.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

MIME 형식을 ResponseCompressionOptions.MimeTypes를 사용하여 바꾸거나 추가합니다. text/*와 같은 와일드카드 MIME 형식은 지원되지 않습니다. 샘플 앱은 MIME 형식을 image/svg+xml 추가하고 압축하며 ASP.NET Core 배너 이미지 banner.svg 제공합니다.

using Microsoft.AspNetCore.ResponseCompression;
using ResponseCompressionSample;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
    options.Providers.Add<CustomCompressionProvider>();
    options.MimeTypes =
    ResponseCompressionDefaults.MimeTypes.Concat(
        new[] { "image/svg+xml" });
});

var app = builder.Build();

app.UseResponseCompression();

Vary 헤더 추가

Accept-Encoding 요청 헤더에 따라 응답을 압축하는 경우 압축되지 않거나 압축된 여러 응답 버전이 있을 수 있습니다. 여러 버전이 존재하고 저장한다는 사실을 클라이언트 및 프록시 캐시에 알리기 위해 Vary 헤더는 Accept-Encoding 값과 함께 추가됩니다. 응답 미들웨어는 응답이 압축될 때 Vary 헤더를 자동으로 추가합니다.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

Nginx 역방향 프록시 뒤에 있을 때의 미들웨어 문제

Nginx에서 요청을 프록시하는 경우 Accept-Encoding 헤더가 제거됩니다. Accept-Encoding 헤더를 제거하면 응답 압축 미들웨어가 응답을 압축하지 못하게 됩니다. 자세한 내용은 NGINX: 압축 및 압축 해제를 참조하세요. 이 이슈는 Nginx(dotnet/aspnetcore#5989)에 대한 통과 압축 해결을 통해 추적됩니다.

IIS 동적 압축을 사용하지 않도록 설정

서버 수준에서 구성된 IIS 동적 압축 모듈을 사용하지 않도록 설정하려면 IIS 모듈 비활성화를 참조하세요.

응답 압축 문제 해결

요청 헤더를 설정하고 Accept-Encoding 응답 헤더, 크기 및 본문을 연구할 수 있는 Firefox Browser 개발자와 같은 도구를 사용합니다. 기본적으로 응답 압축 미들웨어는 다음 조건을 충족하는 응답을 압축합니다.

  • Accept-Encoding 헤더에는 br, gzip, * 값 또는 사용자 지정 압축 공급자와 일치하는 사용자 지정 인코딩 값이 있습니다. 값은 identity가 아니어야 하며, 품질 값(qvalue, q)이 0으로 설정되지 않아야 합니다.
  • MIME 형식(Content-Type)을 설정하고 ResponseCompressionOptions에 구성된 MIME 형식과 일치해야 합니다.
  • 요청은 Content-Range 헤더를 포함하지 않아야 합니다.
  • 응답 압축 미들웨어 옵션에서 보안 프로토콜(https)이 구성되지 않은 경우 요청은 비보안 프로토콜(http)을 사용해야 합니다. 보안 콘텐츠 압축을 사용하도록 설정할 때 위에서 설명한 위험을 확인합니다.

Azure 배포 샘플

Azure에 배포된 샘플 앱에는 다음 Program.cs 파일이 있습니다.

using Microsoft.AspNetCore.ResponseCompression;
using ResponseCompressionSample;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
    options.Providers.Add<CustomCompressionProvider>();
    options.MimeTypes =
    ResponseCompressionDefaults.MimeTypes.Concat(
        new[] { "image/svg+xml" });
});

var app = builder.Build();

app.UseResponseCompression();

app.Map("/trickle", async (HttpResponse httpResponse) =>
{
    httpResponse.ContentType = "text/plain;charset=utf-8";

    for (int i = 0; i < 20; i++)
    {
        await httpResponse.WriteAsync("a");
        await httpResponse.Body.FlushAsync();
        await Task.Delay(TimeSpan.FromMilliseconds(50));
    }
});

app.Map("/testfile1kb.txt", () => Results.File(
    app.Environment.ContentRootFileProvider.GetFileInfo("testfile1kb.txt").PhysicalPath,
    "text/plain;charset=utf-8"));

app.Map("/banner.svg", () => Results.File(
    app.Environment.ContentRootFileProvider.GetFileInfo("banner.svg").PhysicalPath,
    "image/svg+xml;charset=utf-8"));

app.MapFallback(() => LoremIpsum.Text);

app.Run();

추가 리소스

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

네트워크 대역폭은 제한된 리소스입니다. 응답 크기를 줄이면 일반적으로 앱의 응답성이 크게 향상됩니다. 페이로드 크기를 줄이는 한 가지 방법은 앱의 응답을 압축하는 것입니다.

샘플 코드 보기 및 다운로드(다운로드 방법)

응답 압축 미들웨어를 사용하는 경우

IIS, Apache 또는 Nginx에서 서버 기반 응답 압축 기술을 사용합니다. 미들웨어의 성능이 모듈의 성능과 일치하지 않을 수 있습니다. HTTP.sys 서버 및 Kestrel 서버는 현재 기본 제공 압축 지원을 제공하지 않습니다.

다음과 같은 경우 응답 압축 미들웨어를 사용합니다.

응답 압축

일반적으로 기본적으로 압축되지 않은 모든 응답은 응답 압축의 이점을 누릴 수 있습니다. 원시적으로 압축되지 않은 응답에는 일반적으로 CSS, JavaScript, HTML, XML 및 JSON이 포함됩니다. PNG 파일과 같이 기본적으로 압축된 자산은 압축하면 안 됩니다. 기본적으로 압축된 응답을 추가로 압축하려는 경우 압축을 처리하는 데 걸린 시간 때문에 크기 및 전송 시간의 추가적인 약간의 감소가 느껴지지 않을 수도 있습니다. 파일의 내용과 압축 효율성에 따라 약 150-1000바이트보다 작은 파일은 압축하지 않도록 합니다. 작은 파일을 압축하는 오버헤드로 인해 압축되지 않은 파일보다 큰 압축된 파일이 생성될 수 있습니다.

클라이언트가 압축된 콘텐츠를 처리할 수 있는 경우 클라이언트는 요청과 함께 Accept-Encoding 헤더를 전송하여 해당 기능을 서버에 알려야 합니다. 서버는 압축된 콘텐츠를 보낼 때 압축된 응답의 인코딩 방법에 대한 정보를 Content-Encoding 헤더에 포함해야 합니다. 미들웨어에서 지원하는 콘텐츠 인코딩 지정 내용은 다음 표에 나와 있습니다.

Accept-Encoding 헤더 값 지원되는 미들웨어 설명
br 예(기본값) Brotli 압축 데이터 형식
deflate 아니요 DEFLATE 압축 데이터 형식
exi 아니요 W3C Efficient XML Interchange
gzip Gzip 파일 형식
identity “인코딩 안 함” 식별자: 응답을 인코딩하지 않아야 합니다.
pack200-gzip 아니요 Java 보관을 위한 네트워크 전송 형식
* 명시적으로 요청되지 않은 사용 가능한 모든 콘텐츠 인코딩

자세한 내용은 IANA 공식 콘텐츠 코딩 목록을 참조하세요.

미들웨어를 사용하면 사용자 지정 Accept-Encoding 헤더 값에 대한 추가 압축 공급자를 추가할 수 있습니다. 자세한 내용은 아래의 사용자 지정 공급자를 참조하세요.

미들웨어는 압축 체계의 우선 순위를 지정하기 위해 클라이언트에서 보낼 때 품질 값(qvalue, q) 가중치를 고려할 수 있습니다. 자세한 내용은 RFC 9110: Accept-Encoding을 참조하세요.

압축 알고리즘은 압축 속도와 압축의 효율성 간에 균형을 유지합니다. 이 컨텍스트의 ‘효과’는 압축 후 출력의 크기를 나타냅니다. 가장 작은 크기는 가장 ‘최적’ 압축을 통해 달성됩니다.

다음 표에서는 압축된 콘텐츠를 요청, 송신, 캐싱 및 수신하는 것과 관련된 헤더에 대해 설명합니다.

헤더 역할
Accept-Encoding 클라이언트에서 서버로 전송되어 클라이언트에 허용되는 콘텐츠 인코딩 스키마를 표시합니다.
Content-Encoding 서버에서 클라이언트로 전송되어 페이로드에 있는 콘텐츠의 인코딩을 나타냅니다.
Content-Length 압축이 발생하면 응답이 압축될 때 본문 내용이 변경되므로 Content-Length 헤더가 제거됩니다.
Content-MD5 압축이 발생하면 본문 내용이 변경되고 해시가 더 이상 유효하지 않기 때문에 Content-MD5 헤더가 제거됩니다.
Content-Type 콘텐츠의 MIME 형식을 지정합니다. 모든 응답은 해당 Content-Type을 지정해야 합니다. 미들웨어는 이 값을 확인하여 응답이 압축되어야 하는지 결정합니다. 미들웨어는 인코딩할 수 있는 기본 MIME 형식 집합을 지정하지만 .MIME 형식을 바꾸거나 추가할 수 있습니다.
Vary 서버에서 Accept-Encoding 값을 클라이언트 및 프록시로 보내는 경우 Vary 헤더는 요청의 Accept-Encoding 헤더 값을 기준으로 응답을 캐시(다르게 지정)해야 한다는 것을 클라이언트나 프록시에 나타냅니다. Vary: Accept-Encoding 헤더를 사용하여 콘텐츠를 반환하게 되면 압축된 응답과 압축되지 않은 응답이 모두 개별적으로 캐시됩니다.

샘플 앱을 사용하여 응답 압축 미들웨어의 기능을 살펴봅니다. 이 샘플은 다음을 보여 줍니다.

  • Gzip 및 사용자 지정 압축 공급자를 사용하는 앱 응답 압축
  • 압축을 위해 MIME 형식을 MIME 형식 기본 목록에 추가하는 방법입니다.

구성

다음 코드에서는 기본 MIME 형식 및 압축 공급자(Brotli 및 Gzip)에 대해 응답 압축 미들웨어를 사용하도록 설정하는 방법을 보여 줍니다.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

참고:

  • app.UseResponseCompression은 응답을 압축하는 미들웨어 전에 호출해야 합니다. 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.
  • Fiddler, Firefox Browser Developer와 같은 도구를 사용하여 요청 헤더를 Accept-Encoding 설정하고 응답 헤더, 크기 및 본문을 연구합니다.

Accept-Encoding 헤더 없이 샘플 앱에 요청을 제출하고 응답이 압축되지 않았는지 확인합니다. Content-EncodingVary 헤더가 응답에 없습니다.

Fiddler window showing result of a request without the Accept-Encoding header. The response isn't compressed.

Accept-Encoding: br 헤더(Brotli 압축)를 사용하여 샘플 앱에 요청을 제출하고 응답이 압축되었는지 확인합니다. Content-EncodingVary 헤더가 응답에 있습니다.

Fiddler window showing result of a request with the Accept-Encoding header and a value of br. The Vary and Content-Encoding headers are added to the response. The response is compressed.

공급자

Brotli 압축 공급자

BrotliCompressionProvider를 사용하여 Brotli 압축 데이터 형식으로 응답을 압축합니다.

CompressionProviderCollection에 명시적으로 추가된 압축 공급자가 없는 경우 다음을 수행합니다.

  • Brotli 압축 공급자는 기본적으로 Gzip 압축 공급자와 함께 압축 공급자 배열에 추가됩니다.
  • 클라이언트에서 Brotli 압축 데이터 형식이 지원되는 경우 기본 압축은 Brotli 압축입니다. 클라이언트에서 Brotli를 지원하지 않고 클라이언트가 Gzip 압축을 지원하면 기본 압축은 Gzip입니다.
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

압축 공급자가 명시적으로 추가될 때 Brotli 압축 공급자를 추가해야 합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

BrotliCompressionProviderOptions로 압축 수준을 설정합니다. Brotli 압축 공급자는 기본적으로 가장 빠른 압축 수준(CompressionLevel)으로 설정되며, 이 수준은 가장 효율적인 압축을 생성하지 않을 수도 있습니다. 가장 효율적인 압축이 필요한 경우 최적의 압축을 위해 미들웨어를 구성합니다.

압축 수준 설명
CompressionLevel.Fastest 결과 출력이 최적으로 압축되지 않더라도 압축은 최대한 빨리 완료해야 합니다.
CompressionLevel.NoCompression 압축을 수행하지 않아야 합니다.
CompressionLevel.Optimal 압축을 완료하는 데 시간이 더 걸리더라도 응답을 최적으로 압축해야 합니다.
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<BrotliCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

Gzip 압축 공급자

GzipCompressionProvider를 사용하여 Gzip 파일 형식으로 응답을 압축합니다.

CompressionProviderCollection에 명시적으로 추가된 압축 공급자가 없는 경우 다음을 수행합니다.

  • Gzip 압축 공급자는 기본적으로 Brotli 압축 공급자와 함께 압축 공급자 배열에 추가됩니다.
  • 클라이언트에서 Brotli 압축 데이터 형식이 지원되는 경우 기본 압축은 Brotli 압축입니다. 클라이언트에서 Brotli를 지원하지 않고 클라이언트가 Gzip 압축을 지원하면 기본 압축은 Gzip입니다.
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

압축 공급자가 명시적으로 추가될 때 Gzip 압축 공급자를 추가해야 합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

GzipCompressionProviderOptions로 압축 수준을 설정합니다. Gzip 압축 공급자는 기본적으로 가장 빠른 압축 수준(CompressionLevel)으로 설정되며, 이 수준은 가장 효율적인 압축을 생성하지 않을 수도 있습니다. 가장 효율적인 압축이 필요한 경우 최적의 압축을 위해 미들웨어를 구성합니다.

압축 수준 설명
CompressionLevel.Fastest 결과 출력이 최적으로 압축되지 않더라도 압축은 최대한 빨리 완료해야 합니다.
CompressionLevel.NoCompression 압축을 수행하지 않아야 합니다.
CompressionLevel.Optimal 압축을 완료하는 데 시간이 더 걸리더라도 응답을 최적으로 압축해야 합니다.
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<GzipCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

사용자 지정 공급자

ICompressionProvider를 사용하여 사용자 지정 압축 구현을 만듭니다. EncodingNameICompressionProvider가 생성하는 콘텐츠 인코딩을 나타냅니다. 미들웨어는 이 정보를 사용하여 요청의 Accept-Encoding 헤더에 지정된 목록에 따라 공급자를 선택합니다.

클라이언트는 샘플 앱을 Accept-Encoding: mycustomcompression 헤더와 함께 요청을 제출합니다. 미들웨어는 사용자 지정 압축 구현을 사용하고 Content-Encoding: mycustomcompression 헤더와 함께 응답을 반환합니다. 사용자 지정 압축 구현이 작동하려면 클라이언트는 사용자 지정 인코딩의 압축을 풀 수 있어야 합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}
public class CustomCompressionProvider : ICompressionProvider
{
    public string EncodingName => "mycustomcompression";
    public bool SupportsFlush => true;

    public Stream CreateStream(Stream outputStream)
    {
        // Create a custom compression stream wrapper here
        return outputStream;
    }
}

Accept-Encoding: mycustomcompression 헤더를 사용하여 샘플 앱에 요청을 제출하고 응답 헤더를 관찰합니다. VaryContent-Encoding 헤더가 응답에 있습니다. 응답 본문(표시되지 않음)은 샘플을 통해 압축되지 않습니다. 샘플의 CustomCompressionProvider 클래스에는 압축 구현이 없습니다. 그러나 샘플에서는 이러한 압축 알고리즘을 구현하는 위치를 보여 줍니다.

Fiddler window showing result of a request with the Accept-Encoding header and a value of mycustomcompression. The Vary and Content-Encoding headers are added to the response.

MIME 형식

미들웨어는 압축을 위한 기본 MIME 형식 집합을 지정합니다.

  • application/javascript
  • application/json
  • application/xml
  • text/css
  • text/html
  • text/json
  • text/plain
  • text/xml

MIME 형식을 응답 압축 미들웨어 옵션으로 바꾸거나 추가합니다. text/*와 같은 와일드카드 MIME 형식은 지원되지 않습니다. 샘플 앱은 image/svg+xml에 대한 MIME 형식을 추가하고, ASP.NET Core 배너 이미지(banner.svg)를 압축한 후 제공합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

보안 프로토콜을 사용하여 압축

보안 연결을 통한 압축된 응답은 기본적으로 사용하지 않도록 설정된 EnableForHttps 옵션을 사용하여 제어할 수 있습니다. 동적으로 생성된 페이지와 압축을 사용하면 보안 문제(BREACH예: CRIME 공격)가 발생할 수 있습니다.

Vary 헤더 추가

Accept-Encoding 헤더를 기준으로 응답을 압축하는 경우 여러 압축 버전의 응답 및 압축되지 않은 버전이 있습니다. 여러 버전이 존재하고 저장한다는 사실을 클라이언트 및 프록시 캐시에 알리기 위해 Vary 헤더는 Accept-Encoding 값과 함께 추가됩니다. ASP.NET Core 2.0 이상에서 미들웨어는 응답이 압축 될 때 Vary 헤더를 자동으로 추가합니다.

Nginx 역방향 프록시 뒤에 있을 때의 미들웨어 문제

Nginx에서 요청을 프록시하는 경우 Accept-Encoding 헤더가 제거됩니다. Accept-Encoding 헤더를 제거하면 미들웨어가 응답을 압축하지 못합니다. 자세한 내용은 NGINX: 압축 및 압축 해제를 참조하세요. 이 이슈는 Nginx(dotnet/aspnetcore#5989)에 대한 통과 압축 해결을 통해 추적됩니다.

IIS 동적 압축 작업

앱에 대해 사용하지 않도록 설정할 활성 IIS 동적 압축 모듈을 서버 수준에서 구성한 경우 web.config 파일을 추가하여 모듈을 사용하지 않도록 설정합니다. 보다 자세한 내용은 IIS 모듈 비활성화를 참고하시기 바랍니다.

문제 해결

요청 헤더를 설정하고 Accept-Encoding 응답 헤더, 크기 및 본문을 연구할 수 있는 Fiddler 또는 Firefox Browser Developer와 같은 도구를 사용합니다. 기본적으로 응답 압축 미들웨어는 다음 조건을 충족하는 응답을 압축합니다.

  • Accept-Encoding 헤더는 br, gzip, * 또는 설정한 사용자 지정 압축 공급자와 일치하는 사용자 지정 인코딩의 값을 포함합니다. 값은 identity가 아니어야 하며, 품질 값(qvalue, q)이 0으로 설정되지 않아야 합니다.
  • MIME 형식(Content-Type)을 설정하고 ResponseCompressionOptions에 구성된 MIME 형식과 일치해야 합니다.
  • 요청은 Content-Range 헤더를 포함하지 않아야 합니다.
  • 응답 압축 미들웨어 옵션에서 보안 프로토콜(https)이 구성되지 않은 경우 요청은 비보안 프로토콜(http)을 사용해야 합니다. 보안 콘텐츠 압축을 사용하도록 설정할 때 위에서 설명한 위험을 확인합니다.

추가 리소스