Android 공부/네트워크 통신
Ktor
posite
2026. 2. 21. 16:33
Ktor
- 코틀린으로 비동기 클라이언트 및 서버 앱을 작성할 수 있게 하는 Jetbrains에서 만든 코틀린 프레임워크
- 코틀린 코루틴 기반으로 설계되어 비동기 처리 유리
- iOS, Web 등 코틀린 지원 플랫폼에서 동일한 네트워킹 코드 사용 가능 -> 주로 KMP 프로젝트에서 사용
- 리플렉션을 사용하는 Retrofit보다 속도가 빠르고 메모리 사용량이 적음
- DSL 방식을 사용하여 보다 직관적
- TimeOut 등 HttpClient에서 원하는 기능만 사용 가능
import io.ktor.client.HttpClient import io.ktor.client.engine.android.Android import io.ktor.client.plugins.DefaultRequest import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.defaultRequest import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logger import io.ktor.client.plugins.logging.Logging import io.ktor.client.plugins.observer.ResponseObserver import io.ktor.client.request.accept import io.ktor.client.request.header import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.contentType import io.ktor.serialization.kotlinx.json.json HttpClient(Android) { install(ContentNegotiation) { json( Json { prettyPrint = true isLenient = true useAlternativeNames = true ignoreUnknownKeys = true encodeDefaults = false } ) } install(HttpTimeout) { requestTimeoutMillis = NETWORK_TIME_OUT connectTimeoutMillis = NETWORK_TIME_OUT socketTimeoutMillis = NETWORK_TIME_OUT } install(Logging) { logger = object: Logger { override fun log(message: String) { Log.v("Logger Ktor =>", message) } } level = LogLevel.ALL } install(ResponseObserver) { onResponse { response - > Log.d("HTTP status:", "${response.status.value}") } } install(DefaultRequest) { header(HttpHeaders.ContentType, ContentType.Application.Json) } defaultRequest { contentType(ContentType.Application.Json) accept(ContentType.Application.Json) } } - 서비스에 API 요청 정의 - HttpClient와 Service를 분리하여 구현으며, interface로 정의 후, Impl로 구현하여도 문제 없다. get, post 등 HTTP 통신 전부 가능하며, query parameter의 경우 paramter()를 통해 넣어줄 수 있다.
suspend fun getMealsByCategory(category: String) = client.get { url(getString(R.string.meals_url)) parameter("c", category) } - 헤더를 추가할 때는 람다 안에 headers를 통해 추가할 수 있다
client.get(URL) { headers { append(HttpHeaders.Authorization, "Bearer YOUR_TOKEN_HERE") append("Custom-Header", "MyValue") } } - body는 람다 안에 setBody()를 통해 @Seriablizable 객체를 넣어줌으로서 전달할 수 있다
suspend fun createUser(user: User): HttpResponse { return client.post("https://api.example.com/users") { setBody(user) // @Serializable이 붙은 객체를 그대로 전달 } }