ASP.NET core에서 응답 캐싱Response caching in ASP.NET Core

작성자: John Luo, Rick Anderson, Steve Smith, 및 Luke LathamBy John Luo, Rick Anderson, Steve Smith, and Luke Latham

참고

응답에서 Razor 페이지 캐싱은 이상 ASP.NET Core 2.1에서 사용할 수 있습니다.Response caching in Razor Pages is available in ASP.NET Core 2.1 or later.

예제 코드 살펴보기 및 다운로드 (다운로드 방법)View or download sample code (how to download)

응답 캐싱은 클라이언트나 프록시가 웹 서버에 요청하는 회수를 줄여줍니다.Response caching reduces the number of requests a client or proxy makes to a web server. 또한 응답 캐싱은 웹 서버가 응답을 생성하기 위해 수행해야 하는 작업의 총량도 줄여줍니다.Response caching also reduces the amount of work the web server performs to generate a response. 응답 캐싱은 클라이언트, 프록시, 및 미들웨어가 응답을 캐싱해야 하는 방식을 지시하는 헤더에 의해 제어됩니다.Response caching is controlled by headers that specify how you want client, proxy, and middleware to cache responses.

응답 캐싱 미들웨어를 추가하면 웹 서버가 응답을 캐시할 수 있습니다.The web server can cache responses when you add Response Caching Middleware.

HTTP 기반 응답 캐싱HTTP-based response caching

HTTP 1.1 캐싱 사양은 인터넷 캐시가 동작해야 하는 방식을 기술합니다.The HTTP 1.1 Caching specification describes how Internet caches should behave. 캐싱에 사용되는 가장 기본적인 HTTP 헤더는 Cache-Control로 캐시 지시문을 지정하는 데 사용됩니다.The primary HTTP header used for caching is Cache-Control, which is used to specify cache directives. 지시문은 요청이 클라이언트에서 서버로 전달될 때의 캐싱 동작과 응답이 서버에서 클라이언트로 되돌아올 때의 캐싱 동작을 제어합니다.The directives control caching behavior as requests make their way from clients to servers and as reponses make their way from servers back to clients. 프록시 서버를 통해서 이동하는 요청 및 응답, 그리고 프록시 서버 역시 HTTP 1.1 캐싱 사양을 준수해야 합니다.Requests and responses move through proxy servers, and proxy servers must also conform to the HTTP 1.1 Caching specification.

기본적인 Cache-Control 지시문은 다음 표와 같습니다.Common Cache-Control directives are shown in the following table.

지시문Directive 작업Action
publicpublic 캐시에 응답을 저장할 수 있습니다.A cache may store the response.
privateprivate 공유 캐시는 응답을 저장하지 않습니다.The response must not be stored by a shared cache. 사설 캐시는 응답을 저장하고 재사용할 수 있습니다.A private cache may store and reuse the response.
max-agemax-age 클라이언트는 지정된 초 수보다 오래된 응답을 수락하지 않습니다.The client won't accept a response whose age is greater than the specified number of seconds. 예: max-age=60 (60초), max-age=2592000 (1개월)Examples: max-age=60 (60 seconds), max-age=2592000 (1 month)
no-cacheno-cache 요청 시: 캐시는 저장된 응답을 사용해서 요청에 대응하면 안 됩니다.On requests: A cache must not use a stored response to satisfy the request. 주의: 원본 서버는 클라이언트에 대한 응답을 다시 생성하고 미들웨어는 캐시에 저장된 응답을 갱신해야 합니다.Note: The origin server re-generates the response for the client, and the middleware updates the stored response in its cache.

응답 시: 원본 서버에서 유효성을 검사받지 않은 응답을 후속 요청에 사용하면 안 됩니다.On responses: The response must not be used for a subsequent request without validation on the origin server.
no-storeno-store 요청 시: 캐시가 요청을 저장하지 않습니다.On requests: A cache must not store the request.

응답 시: 캐시가 응답의 모든 부분에서 응답을 저장하지 않습니다.On responses: A cache must not store any part of the response.

캐싱 역할을 수행하는 다른 캐시 헤더는 다음 표와 같습니다.Other cache headers that play a role in caching are shown in the following table.

헤더Header 기능Function
AgeAge 응답이 생성되거나 원본 서버에서 정상적으로 검증된 이후로부터 지난 초 단위의 총 추정 시간.An estimate of the amount of time in seconds since the response was generated or successfully validated at the origin server.
ExpiresExpires 응답이 만료된 것으로 간주되는 날짜/시간.The date/time after which the response is considered stale.
PragmaPragma no-cache 동작 설정에 대한 HTTP/1.0 캐시와의 하위 호환성을 지원하기 위해 존재합니다.Exists for backwards compatibility with HTTP/1.0 caches for setting no-cache behavior. Cache-Control 헤더가 존재할 경우 Pragma 헤더는 무시됩니다. If the Cache-Control header is present, the Pragma header is ignored.
VaryVary 모든 Vary 헤더 필드가 캐시된 응답의 원본 요청 및 새 요청 모두와 일치하지 않는 한 캐시된 응답이 전송되지 않도록 지정합니다.Specifies that a cached response must not be sent unless all of the Vary header fields match in both the cached response's original request and the new request.

HTTP 기반 캐싱은 Cache-Control 지시문을 준수합니다HTTP-based caching respects request Cache-Control directives

Cache-Control 헤더에 대한 HTTP 1.1 캐싱 사양은 캐시에게 클라이언트가 전송하는 유효한 Cache-Control 헤더를 준수할 것을 요구합니다.The HTTP 1.1 Caching specification for the Cache-Control header requires a cache to honor a valid Cache-Control header sent by the client. 클라이언트는 no-cache 헤더 값을 설정한 요청을 전송함으로써 모든 요청에 대해 서버가 새로운 응답을 생성하도록 강제할 수 있습니다.A client can make requests with a no-cache header value and force the server to generate a new response for every request.

HTTP 캐싱의 목적을 고려했을 때 항상 클라이언트의 Cache-Control 요청 헤더를 준수하는 것이 이치에 맞습니다.Always honoring client Cache-Control request headers makes sense if you consider the goal of HTTP caching. 공식 사양에서 캐싱은 클라이언트, 프록시 및 서버 간의 네트워크에서 요청의 대기 시간 및 네트워크 오버헤드를 만족스럽게 줄이기 위한 것입니다.Under the official specification, caching is meant to reduce the latency and network overhead of satisfying requests across a network of clients, proxies, and servers. 원본 서버에서 부하를 제어하기 위한 방법이 필수적인 것은 아닙니다.It isn't necessarily a way to control the load on an origin server.

응답 캐싱 미들웨어를 사용할 때 캐싱 동작에 관해서 개발자가 제어할 수 있는 부분은 현재 존재하지 않으며, 그 이유는 미들웨어가 공식 캐싱 사양을 따르고 있기 때문입니다.There's no current developer control over this caching behavior when using the Response Caching Middleware because the middleware adheres to the official caching specification. 캐시된 응답을 제공하기로 결정할 경우 미들웨어가 요청의 `Cache-Control`` 헤더를 무시하게 구성할 수 있도록 향후에는 미들웨어를 개선할 것입니다.Future enhancements to the middleware will permit configuring the middleware to ignore a request's Cache-Control header when deciding to serve a cached response. 이렇게 하면 미들웨어를 사용할 때 서버의 부하를 보다 세밀하게 제어할 수 있습니다.This will offer you an opportunity to better control the load on your server when you use the middleware.

ASP.NET Core의 다른 캐싱 기술Other caching technology in ASP.NET Core

메모리 내 캐싱In-memory caching

메모리 내 캐싱은 서버의 메모리를 이용해서 캐시된 데이터를 저장합니다.In-memory caching uses server memory to store cached data. 이 방식의 캐싱은 단일 서버나 고정 세션을 사용하는 복수의 서버에 적합합니다.This type of caching is suitable for a single server or multiple servers using sticky sessions. 고정 세션은 클라이언트의 요청이 처리를 위해 항상 동일한 서버로 라우트된다는 것을 뜻합니다.Sticky sessions means that the requests from a client are always routed to the same server for processing.

자세한 내용은 메모리 내 캐시를 참고하시기 바랍니다.For more information, see Cache in-memory.

분산 캐시Distributed Cache

응용 프로그램이 클라우드나 서버 팜에서 호스팅될 때 메모리에 데이터를 저장하려면 분산 캐시를 사용합니다.Use a distributed cache to store data in memory when the app is hosted in a cloud or server farm. 이 캐시는 요청을 처리하는 서버들 간에 서로 공유됩니다.The cache is shared across the servers that process requests. 클라이언트에 대한 캐시 데이터를 사용할 수 있는 경우 클라이언트는 그룹의 어떤 서버에서나 처리할 수 있는 요청을 제출할 수 있습니다.A client can submit a request that's handled by any server in the group if cached data for the client is available. ASP.NET Core는 SQL Server 및 Redis 분산 캐시를 제공합니다.ASP.NET Core offers SQL Server and Redis distributed caches.

자세한 내용은 ASP.NET Core의 캐싱 분산을 참조하세요.For more information, see ASP.NET Core의 캐싱 분산.

캐시 태그 도우미Cache Tag Helper

캐시 태그 도우미를 사용하면 MVC 뷰 또는 Razor 페이지의 콘텐츠를 캐시할 수 있습니다.You can cache the content from an MVC view or Razor Page with the Cache Tag Helper. 캐시 태그 도우미는 메모리 내 캐시에 데이터를 저장합니다.The Cache Tag Helper uses in-memory caching to store data.

자세한 내용은 ASP.NET Core MVC와 캐시 태그 도우미를 참고하시기 바랍니다.For more information, see Cache Tag Helper in ASP.NET Core MVC.

분산 캐시 태그 도우미Distributed Cache Tag Helper

분산 캐시 태그 도우미를 사용하면 분산 클라우드 또는 웹 팜 시나리오에서 MVC 뷰 또는 Razor 페이지의 콘텐츠를 캐시할 수 있습니다.You can cache the content from an MVC view or Razor Page in distributed cloud or web farm scenarios with the Distributed Cache Tag Helper. 분산 캐시 태그 도우미는 SQL Server 또는 Redis에 데이터를 저장합니다.The Distributed Cache Tag Helper uses SQL Server or Redis to store data.

자세한 내용은 분산 캐시 태그 도우미를 참고하시기 바랍니다.For more information, see Distributed Cache Tag Helper.

ResponseCache 특성ResponseCache attribute

ResponseCacheAttribute 는 응답 캐싱이 적절한 헤더를 설정하기 위해서 필요한 매개 변수를 지정합니다.The ResponseCacheAttribute specifies the parameters necessary for setting appropriate headers in response caching.

경고

인증된 클라이언트의 정보를 포함하는 콘텐츠는 캐싱하면 안 됩니다.Disable caching for content that contains information for authenticated clients. 사용자 ID 또는 사용자 로그인 여부와 무관하게 변경되지 않는 콘텐츠만 캐싱해야 합니다.Caching should only be enabled for content that doesn't change based on a user's identity or whether a user is signed in.

VaryByQueryKeys 속성은 지정한 쿼리 키 목록의 값에 따라 저장된 응답을 변경합니다.VaryByQueryKeys varies the stored response by the values of the given list of query keys. 단일 값으로 *를 지정하면 모든 쿼리 문자열 매개 변수별로 미들웨어의 응답이 달라집니다.When a single value of * is provided, the middleware varies responses by all request query string parameters. VaryByQueryKeys 를 사용하려면 ASP.NET Core 1.1 이상이 필요합니다.VaryByQueryKeys requires ASP.NET Core 1.1 or later.

응답 캐싱 미들웨어는 반드시 VaryByQueryKeys 속성을 설정할 수 있어야 합니다. 그렇지 않을 경우 런타임 예외가 발생합니다.The Response Caching Middleware must be enabled to set the VaryByQueryKeys property; otherwise, a runtime exception is thrown. VaryByQueryKeys 속성에 대응하는 HTTP 헤더는 존재하지 않습니다.There isn't a corresponding HTTP header for the VaryByQueryKeys property. 이 속성은 응답 캐싱 미들웨어에 의해서 처리되는 HTTP 기능입니다.The property is an HTTP feature handled by the Response Caching Middleware. 미들웨어가 캐시된 응답을 제공하려면 쿼리 문자열 및 쿼리 문자열 값이 이전 요청과 동일해야 합니다.For the middleware to serve a cached response, the query string and query string value must match a previous request. 예를 들어, 다음 표는 요청 순서에 따른 결과를 보여줍니다.For example, consider the sequence of requests and results shown in the following table.

요청Request 결과Result
http://example.com?key1=value1 서버에서 반환됨Returned from server
http://example.com?key1=value1 미들웨어에서 반환됨Returned from middleware
http://example.com?key1=value2 서버에서 반환됨Returned from server

첫 번째 요청은 서버에서 반환되고 미들웨어에 캐시됩니다.The first request is returned by the server and cached in middleware. 두 번째 요청은 쿼리 문자열이 이전 요청과 일치하기 때문에 미들웨어에서 반환됩니다.The second request is returned by middleware because the query string matches the previous request. 세 번째 요청은 쿼리 문자열 값이 이전 요청과 일치하지 않기 때문에 미들웨어 캐시에 존재하지 않습니다.The third request isn't in the middleware cache because the query string value doesn't match a previous request.

ResponseCacheAttributeResponseCacheFilter를 구성하고 생성하기 위해서 (IFilterFactory를 통해서) 사용됩니다.The ResponseCacheAttribute is used to configure and create (via IFilterFactory) a ResponseCacheFilter. ResponseCacheFilter 적절 한 HTTP 헤더 및 응답의 기능 업데이트 작업을 수행 합니다.The ResponseCacheFilter performs the work of updating the appropriate HTTP headers and features of the response. 필터:The filter:

  • 기존에 존재하는 Vary, Cache-ControlPragma 헤더를 모두 제거합니다.Removes any existing headers for Vary, Cache-Control, and Pragma.
  • ResponseCacheAttribute에 설정된 속성을 기반으로 적절한 헤더를 작성합니다.Writes out the appropriate headers based on the properties set in the ResponseCacheAttribute.
  • VaryByQueryKeys 속성이 설정된 경우 응답 캐싱 HTTP 기능을 갱신합니다.Updates the response caching HTTP feature if VaryByQueryKeys is set.

VaryVary

이 헤더는 VaryByHeader 속성이 설정된 경우에만 작성됩니다.This header is only written when the VaryByHeader property is set. 이 속성은 Vary 헤더의 값을 설정합니다.It's set to the Vary property's value. 다음 예제는 VaryByHeader 속성을 사용합니다:The following sample uses the VaryByHeader property:

[ResponseCache(VaryByHeader = "User-Agent", Duration = 30)]
public IActionResult About2()
{
[ResponseCache(VaryByHeader = "User-Agent", Duration = 30)]
public IActionResult About2()
{

브라우저의 네트워크 도구를 사용하면 응답 헤더를 확인할 수 있습니다.You can view the response headers with your browser's network tools. 다음 그림은 About2 액션 메서드를 갱신했을 때 Edge F12 개발자 도구의 네트워크 탭의 출력을 보여줍니다.The following image shows the Edge F12 output on the Network tab when the About2 action method is refreshed:

About2 액션 메서드 호출 시 Edge F12 개발자 도구의 네트워크 탭의 출력

NoStore 및 Location.NoneNoStore and Location.None

NoStore 속성은 다른 대부분의 속성을 덮어씁니다.NoStore overrides most of the other properties. 이 속성이 true로 설정되면 Cache-Control 헤더가 no-store로 설정됩니다.When this property is set to true, the Cache-Control header is set to no-store. 만약 LocationNone으로 설정되면:If Location is set to None:

  • Cache-Controlno-store,no-cache로 설정됩니다.Cache-Control is set to no-store,no-cache.
  • Pragmano-cache로 설정됩니다.Pragma is set to no-cache.

NoStorefalse로 그리고 LocationNone으로 설정되면, Cache-ControlPragmano-cache로 설정됩니다.If NoStore is false and Location is None, Cache-Control and Pragma are set to no-cache.

일반적으로 오류 페이지에서 NoStoretrue로 설정하는 경우가 많습니다.You typically set NoStore to true on error pages. 예를 들어:For example:

[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
    return View();
}
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
    return View();
}

그 결과 다음과 같은 헤더가 만들어집니다:This results in the following headers:

Cache-Control: no-store,no-cache
Pragma: no-cache

Location 및 DurationLocation and Duration

캐싱을 사용하기 위해서는 Duration을 양수 값으로 설정하고 LocationAny (기본값) 또는 Client이어야 합니다.To enable caching, Duration must be set to a positive value and Location must be either Any (the default) or Client. 이 경우 Cache-Control 헤더는 응답의 max-age가 뒤에 추가된 위치 값으로 설정됩니다.In this case, the Cache-Control header is set to the location value followed by the max-age of the response.

참고

Location 옵션의 AnyClient는 각각 Cache-Control 헤더의 값, publicprivate로 변환됩니다.Location's options of Any and Client translate into Cache-Control header values of public and private, respectively. 앞에서 설명한 것처럼 LocationNone으로 설정하면 Cache-ControlPragma 헤더가 모두 no-cache로 설정됩니다.As noted previously, setting Location to None sets both Cache-Control and Pragma headers to no-cache.

다음은 Duration을 설정하고 Location을 기본 값 그대로 변경하지 않고 생성하는 헤더를 보여주는 예제입니다:Below is an example showing the headers produced by setting Duration and leaving the default Location value:

[ResponseCache(Duration = 60)]
public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    return View();
}
[ResponseCache(Duration = 60)]
public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    return View();
}

이 코드는 다음과 같은 헤더를 생성합니다.This produces the following header:

Cache-Control: public,max-age=60

캐시 프로필Cache profiles

수 많은 컨트롤러 액션 속성마다 ResponseCache 설정을 반복하는 대신, StartupConfigureServices 메서드에서 MVC를 설정할 때 캐시 프로필을 옵션으로 설정할 수 있습니다.Instead of duplicating ResponseCache settings on many controller action attributes, cache profiles can be configured as options when setting up MVC in the ConfigureServices method in Startup. 참조된 캐시 프로필에 지정된 값은 ResponseCache 특성에 의해 기본값으로 사용되며 특성에 지정된 모든 속성에 의해 덮어써집니다.Values found in a referenced cache profile are used as the defaults by the ResponseCache attribute and are overridden by any properties specified on the attribute.

먼저 캐시 프로필을 설정합니다.Setting up a cache profile:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.CacheProfiles.Add("Default",
            new CacheProfile()
            {
                Duration = 60
            });
        options.CacheProfiles.Add("Never",
            new CacheProfile()
            {
                Location = ResponseCacheLocation.None,
                NoStore = true
            });
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.CacheProfiles.Add("Default",
            new CacheProfile()
            {
                Duration = 60
            });
        options.CacheProfiles.Add("Never",
            new CacheProfile()
            {
                Location = ResponseCacheLocation.None,
                NoStore = true
            });
    });
}

그리고 캐시 프로필을 참조합니다:Referencing a cache profile:

[ResponseCache(Duration = 30)]
public class HomeController : Controller
{
    [ResponseCache(CacheProfileName = "Default")]
    public IActionResult Index()
    {
        return View();
    }
[ResponseCache(Duration = 30)]
public class HomeController : Controller
{
    [ResponseCache(CacheProfileName = "Default")]
    public IActionResult Index()
    {
        return View();
    }

ResponseCache 특성은 액션(메서드) 및 컨트롤러(클래스) 모두에 적용할 수 있습니다.The ResponseCache attribute can be applied both to actions (methods) and controllers (classes). 메서드 수준 특성은 클래스 수준 특성에 지정된 설정을 덮어씁니다.Method-level attributes override the settings specified in class-level attributes.

위의 예제에서는 클래스 수준 특성이 30초의 지속 시간을 지정하는 반면, 메서드 수준 특성은 지속 시간이 60초로 설정된 캐시 프로필을 참조하고 있습니다.In the above example, a class-level attribute specifies a duration of 30 seconds, while a method-level attribute references a cache profile with a duration set to 60 seconds.

결과 헤더:The resulting header:

Cache-Control: public,max-age=60

추가 자료Additional resources