웹 서버에서 캐시 헤더를 구현하는 것은 클라이언트와의 통신을 최적화하기 위한 중요한 요소입니다. 캐시 헤더를 올바르게 설정하면 클라이언트는 서버에 다시 요청하지 않고도 캐시된 리소스를 사용할 수 있습니다.
코틀린으로 구현된 웹 서버에서 캐시 헤더를 설정하는 방법을 알아보겠습니다.
1. 캐시 헤더 생성
Cache-Control
헤더를 사용하여 캐시 정책을 설정할 수 있습니다. CacheControl
클래스를 사용하여 캐시 헤더를 생성합니다.
import io.ktor.http.CacheControl
import io.ktor.http.Headers
...
val cacheControl = CacheControl.MaxAge(maxAgeSeconds = 3600)
val headers = Headers.build {
append(Headers.CacheControl, cacheControl.toString())
}
위의 예제에서는 캐시의 최대 기간을 1시간으로 설정하고 있습니다.
2. 응답에 캐시 헤더 추가
Ktor 웹 서버에서는 응답에 헤더를 추가하는 방법으로 call.respond
함수를 사용합니다. ApplicationCall
객체의 respond
함수를 호출할 때 headers
매개변수를 사용하여 응답에 캐시 헤더를 추가할 수 있습니다.
import io.ktor.application.call
import io.ktor.response.respond
...
call.respond(status, headers) {
// 응답 본문
// ...
}
위의 예제에서는 call.respond
함수의 두 번째 매개변수로 headers
객체를 전달하여 캐시 헤더를 추가하고 있습니다.
3. 조건부 요청
클라이언트가 서버에 조건부 요청을 할 수 있도록 ETag
헤더를 추가하는 것도 중요합니다. ETag
는 리소스의 고유 식별자로 사용되며, 클라이언트는 이 값을 이용하여 리소스가 변경되었는지 확인할 수 있습니다.
val eTag = generateETag(resource)
headers.append(HttpHeaders.ETag, eTag)
위의 예제에서는 generateETag
함수를 사용하여 리소스의 ETag
값을 생성하고, 이 값을 headers
객체에 추가하고 있습니다.
4. 조건부 요청 처리
클라이언트 요청이 조건부 요청일 경우, 서버는 리소스의 상태를 확인하여 새로운 리소스를 제공해야 할 지 결정합니다. Ktor 웹 서버에서는 ETag
헤더를 검사하여 조건부 요청을 처리할 수 있습니다.
val ifNoneMatch = call.request.header(HttpHeaders.IfNoneMatch)
if (ifNoneMatch == eTag) {
call.respond(HttpStatusCode.NotModified)
} else {
call.respond(status, headers) {
// 응답 본문
// ...
}
}
위의 예제에서는 클라이언트가 보낸 IfNoneMatch
헤더의 값이 ETag
값과 일치하는지 확인하고, 일치할 경우 304 응답 코드를 반환하고 일치하지 않을 경우 캐시 헤더가 포함된 응답을 반환하고 있습니다.
참고 자료
- Ktor 공식 문서: https://ktor.io/docs/conditional-requests.html