ASP.NET 코어 의 응답 압축 실현
응답 압축 기술 은 현재 웹 개발 분야 에서 비교적 자주 사용 되 는 기술 로 대역 폭 자원 이 제 한 된 상황 에서 압축 기술 을 사용 하 는 것 이 대역 폭 부 하 를 향상 시 키 는 최 우선 방안 이다.우리 가 잘 아 는 웹 서버,예 를 들 어 IIS,Tomcat,Nginx,Apache 등 은 모두 압축 기술 을 사용 할 수 있 습 니 다.자주 사용 하 는 압축 유형 은 Brotli,Gzip,Deflate 를 포함 합 니 다.그들 은 CSS,JavaScript,HTML,XML 과 JSON 등 유형 에 대한 효과 가 비교적 뚜렷 하지만 그림 자체 가 압축 형식 이기 때 문 입 니 다.그 다음으로 약 150-1000 바이트 이하 의 파일(구체 적 으로 파일 의 내용 과 압축 의 효율 에 달 려 있 고 작은 파일 을 압축 하 는 비용 은 압축 되 지 않 은 파일 보다 더 큰 압축 파일 이 생 길 수 있 습 니 다.ASP.NET Core 에서 우 리 는 매우 간단 한 방식 으로 응답 압축 을 사용 할 수 있다.
사용 방법\#
ASP.NET Core 에서 압축 에 응답 하 는 방식 을 사용 하 는 것 은 비교적 간단 하 다.우선,Configure Services 에 services.AddResponse Compression 주입 응답 압축 과 관련 된 설정 을 추가 합 니 다.예 를 들 어 사용 하 는 압축 유형,압축 단계,압축 목표 유형 등 입 니 다.그 다음으로 Configure 에 app.UseResponse Compression 차단 요청 을 추가 하여 압축 이 필요 한 지 여 부 를 판단 합 니 다.대체적으로 사용 방식 은 다음 과 같 습 니 다.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCompression();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCompression();
}
}
사용자 정의 설정 이 필요 하 다 면 압축 도 수 동 으로 설정 할 수 있 습 니 다.
public void ConfigureServices(IServiceCollection services)
{
services.AddResponseCompression(options =>
{
// ,
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
//
options.Providers.Add<MyCompressionProvider>();
// MimeType
options.MimeTypes =
ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/json" });
});
// ,
services.Configure<GzipCompressionProviderOptions>(options =>
{
// ,
options.Level = CompressionLevel.Fastest;
//
//options.Level = CompressionLevel.NoCompression;
// ,
//options.Level = CompressionLevel.Optimal;
});
}
압축 에 응답 하 는 대체적인 작업 방식 은 Http 요청 을 할 때 Request Header 에 Accept-Encoding:gzip 또는 원 하 는 압축 형식 을 추가 하면 여러 종 류 를 전달 할 수 있 습 니 다.서버 에서 요청 을 받 아 Accept-Encoding 을 가 져 와 서 이 유형의 압축 방식 을 지원 하 는 지 판단 합 니 다.지원 하면 압축 출력 내용 과 관련 되 고 Content-Encoding 을 현재 사용 하고 있 는 압축 방식 으로 설정 하여 함께 되 돌려 줍 니 다.클 라 이언 트 가 응답 을 받 은 후에 Content-Encoding 을 가 져 와 서 서버 가 압축 기술 을 사 용 했 는 지 판단 하고 해당 하 는 값 에 따라 어떤 압축 유형 을 사 용 했 는 지 판단 한 다음 에 해당 하 는 압축 해제 알고리즘 을 사용 하여 원시 데 이 터 를 얻 었 습 니 다.소스 코드 탐구\#
위의 소 개 를 통 해 여러분 들 이 Response Compression 에 대해 어느 정도 알 게 되 었 을 것 이 라 고 믿 습 니 다.그 다음 에 우 리 는 소스 코드 를 보 는 방식 으로 그의 대체적인 작업 원 리 를 알 아 보 겠 습 니 다.
AddResponseCompression#
먼저 주입 과 관련 된 코드 를 살 펴 보 겠 습 니 다.구체 적 인 코드 는 Response Compression Services Extensions 확장 클래스 에 탑재 되 어 있 습 니 다.[클릭 하여 원본 코드 보기👈]
public static class ResponseCompressionServicesExtensions
{
public static IServiceCollection AddResponseCompression(this IServiceCollection services)
{
services.TryAddSingleton<IResponseCompressionProvider, ResponseCompressionProvider>();
return services;
}
public static IServiceCollection AddResponseCompression(this IServiceCollection services, Action<ResponseCompressionOptions> configureOptions)
{
services.Configure(configureOptions);
services.TryAddSingleton<IResponseCompressionProvider, ResponseCompressionProvider>();
return services;
}
}
주로 ResponseCompressionProvider 와 ResponseCompressionOptions 를 주입 합 니 다.먼저 ResponseCompressionOptions[클릭 하여 원본 코드 보기👈]에 대해 알 아 보 겠 습 니 다.
public class ResponseCompressionOptions
{
//
public IEnumerable<string> MimeTypes { get; set; }
//
public IEnumerable<string> ExcludedMimeTypes { get; set; }
// https
public bool EnableForHttps { get; set; } = false;
//
public CompressionProviderCollection Providers { get; } = new CompressionProviderCollection();
}
이런 종류 에 대해 서 는 소 개 를 많이 하지 않 는 것 이 비교적 간단 하 다.Response Compression Provider 는 우리 가 응답 압축 알고리즘 을 제공 하 는 핵심 클래스 로 구체 적 으로 압축 알고리즘 을 자동 으로 선택 하 는 방법 은 모두 그것 이 제공 하 는 것 입 니 다.이런 유형의 코드 가 비교적 많 기 때문에 우 리 는 한 가지 방법 으로 설명 하지 않 을 것 이다.구체 적 인 소스 코드 는 스스로[클릭 하여 원본 코드 보기👈]을 조회 할 수 있다.먼저 우 리 는 Response Compression Provider 의 구조 함 수 를 먼저 볼 수 있다.
public ResponseCompressionProvider(IServiceProvider services, IOptions<ResponseCompressionOptions> options)
{
var responseCompressionOptions = options.Value;
_providers = responseCompressionOptions.Providers.ToArray();
// Br Gzip
if (_providers.Length == 0)
{
_providers = new ICompressionProvider[]
{
new CompressionProviderFactory(typeof(BrotliCompressionProvider)),
new CompressionProviderFactory(typeof(GzipCompressionProvider)),
};
}
// CompressionProviderFactory Provider GzipCompressionProvider
for (var i = 0; i < _providers.Length; i++)
{
var factory = _providers[i] as CompressionProviderFactory;
if (factory != null)
{
_providers[i] = factory.CreateInstance(services);
}
}
// text/plain、text/css、text/html、application/javascript、application/xml
//text/xml、application/json、text/json、application/was
var mimeTypes = responseCompressionOptions.MimeTypes;
if (mimeTypes == null || !mimeTypes.Any())
{
mimeTypes = ResponseCompressionDefaults.MimeTypes;
}
// MimeType HashSet
_mimeTypes = new HashSet<string>(mimeTypes, StringComparer.OrdinalIgnoreCase);
_excludedMimeTypes = new HashSet<string>(
responseCompressionOptions.ExcludedMimeTypes ?? Enumerable.Empty<string>(),
StringComparer.OrdinalIgnoreCase
);
_enableForHttps = responseCompressionOptions.EnableForHttps;
}
그 중에서 Brotli copression Provider,Gzip Compression Provider 는 구체 적 으로 압축 방법 을 제공 하 는 곳 입 니 다.우 리 는 비교적 자주 사용 하 는 Gzip 의 Provider 의 대체적인 실현[클릭 하여 원본 코드 보기👈]을 살 펴 보 겠 습 니 다.
public class GzipCompressionProvider : ICompressionProvider
{
public GzipCompressionProvider(IOptions<GzipCompressionProviderOptions> options)
{
Options = options.Value;
}
private GzipCompressionProviderOptions Options { get; }
// Encoding
public string EncodingName { get; } = "gzip";
public bool SupportsFlush => true;
// GZipStream
// Level
public Stream CreateStream(Stream outputStream)
=> new GZipStream(outputStream, Options.Level, leaveOpen: true);
}
Response Compression Provider 와 관련 된 다른 방법 에 대해 서 는 UseResponse Compression 미들웨어 를 설명 할 때 구체 적 으로 볼 때 사용 하 는 방법 을 설명 합 니 다.이 종 류 는 압축 에 응 하 는 핵심 류 이기 때문에 지금 미리 말 하면 미들웨어 가 사용 하 는 곳 에서 잊 어 버 릴 수 있 습 니 다.다음은 UseResponse Compression 의 대략적인 실현 을 살 펴 보 겠 습 니 다.UseResponseCompression#
UseResponse Compression 은 구체 적 으로 인삼 이 없 는 확장 방법 이 고 간단 합 니 다.설정 과 작업 이 모두 주 입 된 곳 에서 이 루어 졌 기 때문에 우 리 는 중간 부품 의 실현 을 직접 살 펴 보고 중간 부품 의 위 치 를 찾 습 니 다 Response Compression Middleware[클릭 하여 원본 코드 보기👈]
public class ResponseCompressionMiddleware
{
private readonly RequestDelegate _next;
private readonly IResponseCompressionProvider _provider;
public ResponseCompressionMiddleware(RequestDelegate next, IResponseCompressionProvider provider)
{
_next = next;
_provider = provider;
}
public async Task Invoke(HttpContext context)
{
// Accept-Encoding , " "
if (!_provider.CheckRequestAcceptsCompression(context))
{
await _next(context);
return;
}
// Body
var originalBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
var originalCompressionFeature = context.Features.Get<IHttpsCompressionFeature>();
// Body
var compressionBody = new ResponseCompressionBody(context, _provider, originalBodyFeature);
// Body
context.Features.Set<IHttpResponseBodyFeature>(compressionBody);
context.Features.Set<IHttpsCompressionFeature>(compressionBody);
try
{
await _next(context);
await compressionBody.FinishCompressionAsync();
}
finally
{
// Body
context.Features.Set(originalBodyFeature);
context.Features.Set(originalCompressionFeature);
}
}
}
이 중간 부품 은 Response Compression Body 를 초기 화 하 는 것 이 매우 간단 하 다.여기 서 보면 궁금 할 수도 있 습 니 다.호출 압축 과 관련 된 코드 가 트리거 되 지 않 았 습 니 다.Response Compression Body 도 Finish Compression Async 만 호출 되 었 습 니 다.서 두 르 지 마 세 요.Response Compression Body 류 의 구 조 를 보 겠 습 니 다.
internal class ResponseCompressionBody : Stream, IHttpResponseBodyFeature, IHttpsCompressionFeature
{
}
이 종 류 는 IHttpResponse Body Feature 를 실 현 했 습 니 다.우리 가 사용 하 는 Response.Body 는 사실 얻 은 HttpResponse Body Feature.stream 속성 입 니 다.우리 가 사용 하 는 Response.Write Async 와 관련 된 방법 은 내부 적 으로 모두 PipeWriter 를 호출 하여 쓰기 작업 을 하고 있 으 며,PipeWriter 는 Http Response Body Feature.Writer 속성 에서 나 온 것 입 니 다.출력 과 관련 된 작업 의 핵심 은 IHttpResponse Body Feature 를 조작 하 는 것 으로 요약 된다.관심 있 는 사람 은 HttpResponse 와 관련 된 소스 코드 를 직접 찾 아 보면 관련 정 보 를 알 수 있 습 니 다.그래서 저희 Response Compression Body 는 출력 작업 과 관련 된 방법 을 다시 썼 습 니 다.즉,Response 와 관련 된 Write 나 Body 와 관련 된 것 을 호출 하면 본질은 IHttp Response Body Feature 를 조작 하 는 것 이다.우 리 는 응답 출력 과 관련 된 미들웨어 를 열 었 기 때문에 IHttp Response Body Feature 의 실현 류 Response Compression Body 와 관련 된 방법 으로 출력 을 완성 할 것 이다.우리 가 일반적으로 이해 하 는 것 과 차이 가 있다.일반적인 상황 에서 우 리 는 출력 된 Stream 에 대해 조작 을 하면 된다 고 생각 하지만 압축 미들웨어 에 응답 하여 출력 과 관련 된 조작 을 다시 썼 다.이것 을 알 게 된 후 에는 모두 가 그다지 의문 이 없 을 것 이 라 고 믿는다.Response Compression Body 는 출력 과 관련 된 조작 을 다시 썼 기 때문에 코드 가 상대 적 으로 많 기 때문에 하나씩 붙 이지 않 습 니 다.우 리 는 압축 핵심 과 관련 된 코드 만 볼 수 있 습 니 다.Response Compression Body 소스 코드 와 관련 된 세부 사항 에 관심 이 있 으 면[클릭 하여 원본 코드 보기👈]을 조회 할 수 있 습 니 다.수출 의 본질은 모두 Write 방법 을 호출 하 는 것 입 니 다.Write 방법 과 관련 된 실현 을 살 펴 보도 록 하 겠 습 니 다.
public override void Write(byte[] buffer, int offset, int count)
{
//
OnWrite();
//_compressionStream OnWrite
if (_compressionStream != null)
{
_compressionStream.Write(buffer, offset, count);
if (_autoFlush)
{
_compressionStream.Flush();
}
}
else
{
_innerStream.Write(buffer, offset, count);
}
}
위의 코드 를 통 해 우 리 는 OnWrite 방법 이 핵심 조작 이라는 것 을 보 았 다.우 리 는 OnWrite 방법 이 실현 되 는 지 직접 보 았 다.
private void OnWrite()
{
if (!_compressionChecked)
{
_compressionChecked = true;
//
if (_provider.ShouldCompressResponse(_context))
{
// Vary
var varyValues = _context.Response.Headers.GetCommaSeparatedValues(HeaderNames.Vary);
var varyByAcceptEncoding = false;
// Vary Accept-Encoding
for (var i = 0; i < varyValues.Length; i++)
{
if (string.Equals(varyValues[i], HeaderNames.AcceptEncoding, StringComparison.OrdinalIgnoreCase))
{
varyByAcceptEncoding = true;
break;
}
}
if (!varyByAcceptEncoding)
{
_context.Response.Headers.Append(HeaderNames.Vary, HeaderNames.AcceptEncoding);
}
// ICompressionProvider
var compressionProvider = ResolveCompressionProvider();
if (compressionProvider != null)
{
// , Content-Encoding
// Content-Encoding
_context.Response.Headers.Append(HeaderNames.ContentEncoding, compressionProvider.EncodingName);
// , Content-MD5 , 。
_context.Response.Headers.Remove(HeaderNames.ContentMD5);
// , Content-Length , , 。
_context.Response.Headers.Remove(HeaderNames.ContentLength);
//
_compressionStream = compressionProvider.CreateStream(_innerStream);
}
}
}
}
private ICompressionProvider ResolveCompressionProvider()
{
if (!_providerCreated)
{
_providerCreated = true;
// ResponseCompressionProvider
_compressionProvider = _provider.GetCompressionProvider(_context);
}
return _compressionProvider;
}
위의 논 리 를 통 해 알 수 있 듯 이 압축 과 관련 된 논 리 를 실행 하기 전에 압축 과 관련 된 방법 을 만족 시 키 는 지 판단 해 야 한다.Should CompressResponse.이 방법 은 Response Compression Provider 의 방법 이다.여 기 는 코드 를 붙 이지 않 는 다.원래 논 리 를 판단 하 는 것 이다.내 가 직접 정리 한 것 은 몇 가지 상황 이다.다음은 Response Compression Provider 의 GetCompression Provider 방법 을 살 펴 보고 어떤 압축 형식 으로 돌아 가 는 지 확인 합 니 다.
public virtual ICompressionProvider GetCompressionProvider(HttpContext context)
{
var accept = context.Request.Headers[HeaderNames.AcceptEncoding];
// Accept-Encoding
if (StringValues.IsNullOrEmpty(accept))
{
Debug.Assert(false, "Duplicate check failed.");
return null;
}
// Accept-Encoding , gzip、br、identity ,
if (!StringWithQualityHeaderValue.TryParseList(accept, out var encodings) || !encodings.Any())
{
return null;
}
//
var candidates = new HashSet<ProviderCandidate>();
foreach (var encoding in encodings)
{
var encodingName = encoding.Value;
//Quality ,
var quality = encoding.Quality.GetValueOrDefault(1);
//quality 0
if (quality < double.Epsilon)
{
continue;
}
// encodingName providers EncodingName
// providers
for (int i = 0; i < _providers.Length; i++)
{
var provider = _providers[i];
if (StringSegment.Equals(provider.EncodingName, encodingName, StringComparison.OrdinalIgnoreCase))
{
candidates.Add(new ProviderCandidate(provider.EncodingName, quality, i, provider));
}
}
// EncodingName * providers
if (StringSegment.Equals("*", encodingName, StringComparison.Ordinal))
{
for (int i = 0; i < _providers.Length; i++)
{
var provider = _providers[i];
candidates.Add(new ProviderCandidate(provider.EncodingName, quality, i, provider));
}
break;
}
// EncodingName identity ,
if (StringSegment.Equals("identity", encodingName, StringComparison.OrdinalIgnoreCase))
{
candidates.Add(new ProviderCandidate(encodingName.Value, quality, priority: int.MaxValue, provider: null));
}
}
ICompressionProvider selectedProvider = null;
//
if (candidates.Count <= 1)
{
selectedProvider = candidates.FirstOrDefault().Provider;
}
else
{
// Quality Priority
selectedProvider = candidates
.OrderByDescending(x => x.Quality)
.ThenBy(x => x.Priority)
.First().Provider;
}
// selectedProvider identity null
if (selectedProvider == null)
{
return null;
}
return selectedProvider;
}
이상 의 소 개 를 통 해 우 리 는 압축 에 응 하 는 대체적인 작업 방식 을 대충 알 수 있 고 간단하게 정리 할 수 있다.관련 코드 를 보기 전에 압축 에 응 하 는 논리 가 매우 간단 할 것 이 라 고 생각 했 는데 소스 코드 를 보고 나 서 야 자신 이 생각 하 는 것 이 너무 간단 하 다 는 것 을 알 게 되 었 다.그 중에서 자신의 생각 과 가장 큰 차이 가 있 는 것 은 Response Compression Middleware 미들웨어 미들웨어 에서 출력 흐름 을 통일 적 으로 차단 하여 압축 작업 을 하 는 줄 알 았 는데 전체 출력 작업 을 재 작성 하 는 것 이 라 고 생각 하지 못 했다.이전에 우리 가 Asp.Net 관련 프레임 워 크 를 사용 할 때 Filter 나 HttpModule 을 통일 적 으로 써 서 처 리 했 기 때문에 사고방식 이 존재 한다.아마도 Asp.Net 코어 디자이너 가 더 깊 은 이 해 를 가지 고 있 을 것 입 니 다.제 가 아직 철저하게 이해 하지 못 했 기 때문에 이렇게 하 는 장점 이 무엇 인지 이해 할 수 없습니다.만약 에 더 좋 은 이해 가 있 거나 답 이 있 으 면 댓 글 에 댓 글 을 달 아 의혹 을 풀 어 주 십시오.
여기 서 ASP.NET Core 의 응답 압축 실현 에 관 한 글 을 소개 합 니 다.더 많은 관련 ASP.NET Core 응답 압축 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
부트스트랩 ASP.NET에서 설정하는 법1) _Layout.cshtml 內 link로 bootstrap 참조 2) Nuget 패키지에서 BootStrap 다운로드 3) 하단 부트스트랩 예제 사이트 참고해서 프로젝트 개발 참고 :...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.