OkHttp — định nghĩa, tính năng và kiến trúc của HTTP client

Tác giả: IT Sectr Đã đăng: 2026-03-07 Thời gian đọc: 8 phút

OkHttp là một HTTP client hiệu suất cao cho Android và Kotlin, được Square phát triển làm nền tảng cho Retrofit và các thư viện mạng khác. Nó cung cấp quản lý kết nối hiệu quả, bộ nhớ đệm tích hợp và hỗ trợ HTTP/2. Theo Square, 2025, OkHttp xử lý hàng tỷ yêu cầu mỗi ngày trong các ứng dụng trên toàn thế giới.

Điểm chính

  • OkHttp — HTTP client cho Android và Kotlin từ Square với hỗ trợ HTTP/2 và SPDY
  • Connection Pool — cơ chế tái sử dụng kết nối TCP để giảm độ trễ
  • Interceptor — Interceptor và NetworkInterceptor sửa đổi yêu cầu và phản hồi
  • Caching — Cache tích hợp giảm lưu lượng truy cập cho các yêu cầu lặp lại
  • WebSocket — hỗ trợ giao tiếp hai chiều qua giao thức WebSocket

OkHttp là gì?

OkHttp là một HTTP client hiệu quả cho Java, Android và Kotlin, do Square phát triển. Thư viện cung cấp API cấp thấp để thực hiện các yêu cầu HTTP với hỗ trợ HTTP/2, SPDY, WebSocket và tự động khôi phục kết nối khi mạng gặp sự cố.

OkHttp ra đời vào năm 2013 như một phản ứng trước nhu cầu về một HTTP client đáng tin cậy giải quyết các vấn đề của HttpURLConnection — thiếu connection pool, hỗ trợ HTTP/2 yếu và API bất tiện. Đến năm 2025, OkHttp được sử dụng ở cấp hệ thống Android API: OkHttp được tích hợp vào triển khai HttpURLConnection từ Android 4.4 (API 19).

Theo Google I/O 2024, OkHttp xử lý hơn 70% tổng số yêu cầu HTTP trong hệ sinh thái Android. Điều này khả thi vì OkHttp hoạt động như lớp vận chuyển cho Retrofit, Apollo GraphQL, Firebase và nhiều thư viện khác. Nhà phát triển nhận được chức năng OkHttp một cách tự động mà không cần thêm nó một cách tường minh.

Cách OkHttp hoạt động

Kiến trúc OkHttp được xây dựng trên chuỗi interceptor. Mỗi yêu cầu đi qua một chuỗi các interceptor có thể sửa đổi Request, Response hoặc ngừng thực thi. Kiến trúc này tương tự mẫu Chain of Responsibility và cho phép mở rộng linh hoạt.

Khi một ứng dụng gửi yêu cầu, OkHttp thực hiện các bước sau: giải quyết DNS, chọn kết nối từ pool (hoặc tạo mới), mở bắt tay TLS (nếu HTTPS), gửi yêu cầu HTTP, nhận phản hồi và trả về cho ứng dụng. RealCall là lớp nội bộ quản lý toàn bộ vòng đời của một yêu cầu từ khi tạo đến khi hoàn thành.

OkHttp tự động xử lý chuyển hướng (302, 301), thử lại yêu cầu khi mạng gặp sự cố, tuân thủ giao thức keep-alive và hỗ trợ nén gzip trong suốt. Nhà phát triển không cần viết mã cho các thao tác này — OkHttp thực hiện chúng tự động dựa trên các header của máy chủ.

Hỗ trợ HTTP/2 và ghép kênh

HTTP/2 cho phép gửi nhiều yêu cầu đồng thời qua một kết nối TCP duy nhất, không bị chặn head-of-line (đặc trưng của HTTP/1.1). OkHttp tự động sử dụng HTTP/2 nếu máy chủ hỗ trợ và chuyển về HTTP/1.1 một cách trong suốt khi cần thiết.

Ghép kênh HTTP/2 đặc biệt quan trọng đối với các ứng dụng di động, nơi độ trễ thiết lập kết nối (TCP + TLS) có thể là 100–300 ms. Thay vì 10 kết nối tuần tự, OkHttp sử dụng một kết nối, giảm độ trễ tổng thể xuống 40–60% trên các thiết bị Android điển hình có kết nối không ổn định.

Interceptor của OkHttp: Interceptor và NetworkInterceptor

Interceptor là một giao diện với một phương thức duy nhất intercept(Chain), nhận Request, thực hiện các hành động và trả về Response. Có hai loại interceptor: interceptor ứng dụng (được thêm qua addInterceptor) và interceptor mạng (addNetworkInterceptor).

Các interceptor ứng dụng kích hoạt trước khi hình thành yêu cầu HTTP — chúng thấy Request gốc và Response cuối cùng sau tất cả các biến đổi. Interceptor mạng kích hoạt ở cấp mạng: chúng thấy yêu cầu sau khi nén gzip, thêm header Content-Length, chuyển hướng và thử lại. Interceptor mạng không được gọi nếu phản hồi được lấy từ bộ nhớ đệm.

Loại InterceptorPhương thức thêmKhi nào được gọiThấy cache
Application InterceptoraddInterceptor()Trước và sau yêu cầu
Network InterceptoraddNetworkInterceptor()Ở cấp mạngKhông

Ứng dụng thực tế của Interceptor

Trong thực tế, các interceptor của OkHttp giải quyết ba nhiệm vụ chính: ủy quyền (thêm header Authorization), ghi log (HttpLoggingInterceptor để gỡ lỗi) và thử lại (tự động lặp lại yêu cầu khi mạng gặp sự cố). Bằng cách kết hợp nhiều interceptor, có thể xây dựng một pipeline xử lý yêu cầu hoàn chỉnh mà không trùng lặp mã trong mỗi lần gọi HTTP của ứng dụng.

Thứ tự thêm interceptor rất quan trọng: Interceptor được thêm đầu tiên sẽ thực thi đầu tiên khi vào và cuối cùng khi ra. Đối với NetworkInterceptor, thứ tự được xác định bởi ngăn xếp mạng. Thứ tự được khuyên dùng: AuthInterceptor (thêm token), LoggingInterceptor (ghi log yêu cầu), RetryInterceptor (thử lại khi thất bại).

Ghi log qua HttpLoggingInterceptor

Để gỡ lỗi các yêu cầu mạng, HttpLoggingInterceptor được sử dụng — một interceptor có sẵn từ Square. Nó ghi log phương thức, URL, header và nội dung yêu cầu/phản hồi. Các cấp độ ghi log: BASIC (phương thức + URL + mã), HEADERS (có header) và BODY (yêu cầu và phản hồi đầy đủ). BODY hữu ích trong quá trình phát triển nhưng bị vô hiệu hóa trong môi trường sản xuất vì lý do bảo mật và hiệu suất.

Ví dụ mã OkHttp trong Kotlin

Hãy xem xét một yêu cầu GET cơ bản sử dụng OkHttp. Đầu tiên, OkHttpClient được tạo — một đối tượng nặng được tạo một lần và tái sử dụng. Sau đó, một Request được hình thành với URL và yêu cầu được thực thi đồng bộ qua execute hoặc bất đồng bộ qua enqueue.

kotlin
val client = OkHttpClient.Builder()
    .connectTimeout(15, TimeUnit.SECONDS)
    .readTimeout(15, TimeUnit.SECONDS)
    .build()

val request = Request.Builder()
    .url("https://api.github.com/users/octocat")
    .header("Accept", "application/vnd.github.v3+json")
    .build()

val response = client.newCall(request).execute()
println(response.body()?.string())

Đối với thực thi bất đồng bộ, phương thức enqueue được sử dụng, chấp nhận một Callback. OkHttp thực thi yêu cầu trong một luồng nền và trả về kết quả trong callback trên cùng một luồng. Để chuyển sang luồng chính của Android, hãy sử dụng Handler hoặc coroutines.

kotlin
client.newCall(request).enqueue(object : Callback {
    override fun onFailure(
        call: Call, e: IOException
    ) {
        println("Yêu cầu thất bại: ${e.message}")
    }

    override fun onResponse(
        call: Call, response: Response
    ) {
        println(response.body()?.string())
    }
})

Thêm Interceptor cho ủy quyền

Một Interceptor tùy chỉnh thêm token Bearer vào mỗi yêu cầu. Interceptor kiểm tra sự hiện diện của header Authorization và nếu token chưa được đặt, sẽ thêm nó từ bộ nhớ lưu trữ. Khi nhận được phản hồi 401, interceptor có thể làm mới token qua Authenticator.

kotlin
class AuthInterceptor(
    private val tokenProvider: () -> String?
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val token = tokenProvider.invoke()
        val request = originalRequest.newBuilder()
            .header("Authorization", "Bearer $token")
            .build()
        return chain.proceed(request)
    }
}

Connection Pool và Caching trong OkHttp

Connection Pool (ConnectionPool) là một tối ưu hóa chính của OkHttp cho phép tái sử dụng các kết nối TCP cho nhiều yêu cầu. Thay vì tạo một socket mới cho mỗi yêu cầu, OkHttp lưu trữ tối đa 5 kết nối không hoạt động (mặc định) trong 5 phút, giảm độ trễ 30–70% cho các yêu cầu lặp lại đến cùng một máy chủ.

Bộ nhớ đệm phản hồi được triển khai qua lớp Cache. Để bật bộ nhớ đệm, chỉ cần chỉ định thư mục và kích thước tối đa trong OkHttpClient.Builder. OkHttp tự động lưu vào bộ nhớ đệm các phản hồi GET theo các header Cache-Control, Expires và ETag, trả về dữ liệu đã lưu vào bộ nhớ đệm mà không cần yêu cầu mạng nếu chúng chưa hết hạn.

kotlin
val cacheDir = File(context.cacheDir, "http-cache")
val cache = Cache(cacheDir, 10L * 1024 * 1024)

val client = OkHttpClient.Builder()
    .cache(cache)
    .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
    .build()

Việc cấu hình đúng pool và bộ nhớ đệm đặc biệt quan trọng đối với các ứng dụng có yêu cầu thường xuyên — bảng tin, trò chuyện, cập nhật dữ liệu. Không có pool, mỗi kết nối TCP yêu cầu bắt tay ba chiều (SYN, SYN-ACK, ACK) và có thể cả bắt tay TLS (2–3 vòng), thêm 100–500 ms vào mỗi yêu cầu.

OkHttp cũng hỗ trợ WebSocket qua lớp RealWebSocket. Kết nối WebSocket được thiết lập thông qua bắt tay HTTP (101 Switching Protocols) và sau đó chuyển sang giao thức hai chiều. OkHttp tự động gửi các khung ping để duy trì kết nối và kết nối lại khi bị ngắt. WebSocket của OkHttp tương thích với các điểm cuối tiêu chuẩn như wss://echo.websocket.org.

Lỗi thường gặp khi làm việc với OkHttp

Tạo OkHttpClient cho mỗi yêu cầu là lỗi phổ biến nhất. OkHttpClient chứa connection pool, cache và thread pool. Tạo một thể hiện mới cho mỗi yêu cầu không chỉ lãng phí bộ nhớ mà còn mất lợi ích của việc tái sử dụng kết nối. OkHttpClient phải là một singleton thông qua bộ chứa DI.

Bỏ qua việc đóng Response.body() dẫn đến rò rỉ tài nguyên. ResponseBody chứa InputStream phải được đóng sau khi đọc. Nếu sử dụng body().string() hoặc body().bytes(), OkHttp tự động đóng luồng, nhưng khi đọc body().byteStream() hoặc body().charStream(), cần gọi close() rõ ràng trong khối finally.

Thiếu xử lý Timeout là một vấn đề khác. Theo mặc định, OkHttp có connectTimeout là 10 giây, readTimeout là 10 giây và writeTimeout là 10 giây. Đối với các ứng dụng di động có kết nối không ổn định, nên đặt connectTimeout là 15–30 giây và readTimeout là 15–30 giây, nếu không người dùng sẽ chờ quá lâu khi tín hiệu yếu.

Câu hỏi thường gặp

OkHttp khác Retrofit như thế nào?

OkHttp là HTTP client cấp thấp với quản lý Request và Response thủ công. Retrofit là lớp trừu tượng cấp cao với các chú thích. OkHttp được sử dụng làm lớp vận chuyển cho Retrofit nhưng cũng có thể hoạt động độc lập mà không cần thư viện bổ sung.

OkHttp xử lý HTTPS như thế nào?

OkHttp sử dụng SSLSocketFactory cho bắt tay TLS. Thư viện hỗ trợ CertificatePinner để ghim chứng chỉ, TrustManager để xác thực tùy chỉnh và HostnameVerifier để kiểm tra tên máy chủ với chứng chỉ.

Làm thế nào để bắt lỗi mạng trong OkHttp?

Các yêu cầu đồng bộ ném IOException khi có sự cố mạng. Các yêu cầu bất đồng bộ nhận được lời gọi onFailure với IOException. Đối với lỗi HTTP (4xx, 5xx), phản hồi được coi là thành công — mã lỗi được kiểm tra qua response.isSuccessful().

OkHttp có hỗ trợ WebSocket không?

Có, OkHttp có hỗ trợ WebSocket tích hợp qua lớp WebSocket và WebSocketListener. Sau khi thiết lập kết nối, WebSocket cho phép gửi và nhận tin nhắn theo thời gian thực mà không cần các yêu cầu HTTP lặp lại.

Làm thế nào để tắt chuyển hướng trong OkHttp?

Tắt chuyển hướng tự động qua followRedirects(false)followSslRedirects(false) trong OkHttpClient.Builder. Điều này hữu ích khi bạn cần xử lý chuyển hướng thủ công, ví dụ, để trích xuất token từ URL chuyển hướng.

Tổng kết

  • OkHttp — HTTP client hiệu suất cao từ Square với hỗ trợ HTTP/2 và SPDY
  • Kiến trúc interceptor triển khai Chain of Responsibility để sửa đổi yêu cầu
  • Connection pool tái sử dụng kết nối TCP, giảm độ trễ 30–70%
  • Caching Cache-Control và ETag giảm lưu lượng cho các yêu cầu lặp lại
  • WebSocket cho phép giao tiếp hai chiều thời gian thực
  • OkHttpClient nên là singleton — tạo một cái cho mỗi yêu cầu dẫn đến rò rỉ
  • ResponseBody yêu cầu đóng rõ ràng khi đọc qua byteStream

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm