OkHttp เป็น HTTP Client สมรรถนะสูงสำหรับ Android และ Kotlin ที่พัฒนาโดย Square เป็นรากฐานของ Retrofit และไลบรารีเครือข่ายอื่นๆ โดยให้การจัดการเชื่อมต่อที่มีประสิทธิภาพ การแคชในตัว และรองรับ HTTP/2 ตามแหล่งข้อมูล Square, 2025 พบว่า OkHttp จัดการคำขอหลายพันล้านรายวันในแอปพลิเคชันทั่วโลก
ข้อเรียนรู้หลัก
OkHttp เป็น HTTP Client ที่มีประสิทธิภาพสำหรับ Java, Android และ Kotlin ที่พัฒนาโดย Square ไลบรารีให้ API ระดับต่ำสำหรับการดำเนินการคำขอ HTTP พร้อมรองรับ HTTP/2, SPDY, WebSocket และการกู้คืนการเชื่อมต่ออัตโนมัติเมื่อเครือข่ายล้มเหลว
OkHttp เกิดขึ้นในปี 2013 เพื่อตอบสนองความต้องการ HTTP Client ที่เชื่อถือได้ซึ่งจะแก้ไขปัญหาของ HttpURLConnection — ขาด connection pool, รองรับ HTTP/2 ที่อ่อนแรง และ API ที่ไม่สะดวก ภายในปี 2025 OkHttp ถูกใช้ในระดับระบบของ Android API: OkHttp ถูกฝังอยู่ในการใช้งาน HttpURLConnection ตั้งแต่ Android 4.4 (API 19)
ตามข้อมูลจาก Google I/O 2024, OkHttp จัดการมากกว่า 70% ของคำขอ HTTP ทั้งหมดในระบนิเวศ Android ทำได้เพราะ OkHttp ทำหน้าที่เป็นชั้นของการส่งต่อสำหรับ Retrofit, Apollo GraphQL, Firebase แลไลบรารีอื่นๆ อีกมาก นักพัฒนาได้รับฟังก์ชันของ OkHttp โดยอัตโนมัติโดยไม่ต้องเพิ่มมันอย่างชัดเจน
สถาปัตยกรรม OkHttp สร้างบนโซ่อิงค์ของ interceptor แต่ละคำขอจะผ่านลำดับของ interceptor ที่สามารถแก้ไขคำขอ, คำตอบ หรือยกเลิกการดำเนินงาน สถาปัตยกรรมนี้คล้ายกับแพทเทิร็น Chain of Responsibility และช่วยให้สามารถขยายได้อย่างยืดหยุ่น
เมื่อแอพพลิเคชันส่งคำขอ, OkHttp จะดำเนินขั้นตอนดังนี้: แก้ DNS, เลือกการเชื่อมต่อจาก pool, เปิด TLS handshake, ส่งคำขอ HTTP, รับคำตอบ และส่งคืนไปยังแอพพลิเคชัน RealCall เป็นคลาสในที่จัดการวงจรของคำขอตั้งแต่การสร้างจนกลับสำเร็จ
OkHttp จัดการเรียกโอนอัตโนมัติ (302, 301), ลองใหม่คำขอเมื่อเครือข่ายล้มเหลว, ปฏิบัติตามโปรโตคอล keep-alive และรองรับการบีบอัด gzip แบบโปร่งใส นักพัฒนาไม่จำเป็นต้องเขียนโค้ดสำหรับการณ์เหล่านี้ — OkHttp ทำได้โดยอัตโนมัติตามหัวข้อของเซิร์ฟเวอร์
HTTP/2 ช่วยให้สามารถส่งหลายคำขอพร้อมกันผ่านการเชื่อมต่อ TCP เดียวโดยไม่มี head-of-line blocking (ซึ่งเป็นลักษณะของ HTTP/1.1) OkHttp จะใช้ HTTP/2 โดยอัตโนมัติหากเซิร์ฟเวอร์รองรับ และจะเปลี่ยนไปใช้ HTTP/1.1 แบบโปร่งใสเมื่อจำเป็น
มัลติเพล็กซิง HTTP/2 สำคัญเฉพาะสำหรับแอพพลิเคชันมือถือ โดยความหน่วงในการตั้งค่าการเชื่อมต่อ (TCP + TLS) อาจอยู่ที่ 100–300 มิลลิวินาที แทนที่จะใช้ 10 การเชื่อมต่อแบบเรียงลำดับ, OkHttp ใช้แค่อันเดียว ซึ่งช่วยลดความหน่วงโดยรวมลง 40–60% บนอุปกรณ์ Android ทั่วไปที่มีการเชื่อมต่อไม่มั่นคง
Interceptor เป็นอินเทอร์เฟสที่มีเมธอดเดียวคือ intercept(Chain) ซึ่งรับคำขอ, ดำเนินการ และส่งคืนคำตอบ มี interceptor สองชนิด: application interceptor (เพิ่มผ่าน addInterceptor) และ network interceptor (addNetworkInterceptor)
Application interceptor ทำงานก่อนการสร้างคำขอ HTTP — พวกมันเห็นคำขอต้นฉบับและคำตอบสุดท้ายหลังการแปลงรูปทั้งหมด Network interceptor ทำงานในระดับเครือข่าย: พวกมันเห็นคำขอหลังการบีบอัด gzip, การเพิ่มหัวข้อ Content-Length, การเรียกโอน และการลองใหม่ Network interceptor จะไม่ถูกเรียกหากคำตอบมาจาก cache
| ชนิด Interceptor | วิธีการเพิ่ม | เมื่อไหนที่ถูกเรียก | เห็น cache |
|---|---|---|---|
| Application Interceptor | addInterceptor() | ก่อนและหลังคำขอ | ใช่ |
| Network Interceptor | addNetworkInterceptor() | ในระดับเครือข่าย | ไม่ |
ในทุกย่างปฏิบัติ interceptor ของ OkHttp แก้ไขสามงานหลัก: การอนุญาต (การเพิ่มหัวข้อ Authorization), การบันทึกล็อก (HttpLoggingInterceptor สำหรับการแก้ไขข้อผิดพลาด) และ การลองใหม่ (การเรียกใช้คำขอใหม่โดยอัตโนมัติเมื่อเครือข่ายล้มเหลว) การรวม interceptor หลายตัวช่วยให้สร้างโปรเซสซิงคำขอที่สมบูรณ์โดยไม่ต้องทำซ้ำโค้ดในทุกการเรียก HTTP ของแอพพลิเคชัน
ลำดับการเพิ่ม interceptor มีความสำคัญ: Interceptor ที่เพิ่มก่อนเพื่อนจะทำงานก่อนเมื่อเข้าและทำงานหลังเมื่อออก สำหรับ NetworkInterceptor ลำดับจะถูกกำหนดโดยเซียร์ก็อ network ลำดับที่แนะนำ: AuthInterceptor (เพิ่ม token), LoggingInterceptor (บันทึกคำขอ), RetryInterceptor (ลองใหม่เมื่อเกิดข้อผิดพลาด)
สำหรับการแก้ไขข้อผิดพลาดคำขอเครือข่าย, HttpLoggingInterceptor ถูกใช้งาน — interceptor พร้อมใช้จาก Square โดยจะบันทึกเมธอด, URL, หัวข้อ และตัวคำขอ/คำตอบ ระดับการบันทึก: BASIC (เมธอด + URL + โค้ด), HEADERS (พร้อมหัวข้อ) และ BODY (คำขอและคำตอบเต็มรูปแบบ) BODY มีประโยชน์ในระหว่างการพัฒนาแต่จะถูกปิดใช้งานในไฟล์ผลิตเพราะเหตุด้านความปลอดภัยและประสิทธิภาพ
มาดูคำขอ GET พื้นฐาน โดยใช้ OkHttp ก่อนอื่นจะสร้าง OkHttpClient — อัตถานที่หนักซึ่งจะถูกสร้างครั้งเดียวและใช้งานซ้ำ จากนั้นจะสร้าง Request พร้อม URL และดำเนินการคำขอแบบซึงโครนัสผ่าน execute หรือแบบอยต์โครนัสผ่าน enqueue
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())
สำหรับ การดำเนินการแบบอยต์โครนัส ใช้เมธอด enqueue ซึ่งรับ Callback OkHttp จะดำเนินคำขอในเส้นด้านหลังและส่งคืนผลลัพธ์ใน callback บนเส้นด้านเดียวกัน หากต้องการเปลี่ยนไปยังเส้นด้านหลักของ Android ให้ใช้ Handler หรือ coroutines
client.newCall(request).enqueue(object : Callback {
override fun onFailure(
call: Call, e: IOException
) {
println("คำขอล้มเหลว: ${e.message}")
}
override fun onResponse(
call: Call, response: Response
) {
println(response.body()?.string())
}
})
Interceptor แบบกำหนดเองจะเพิ่ม Bearer token ในทุกคำขอ Interceptor จะตรวจสอบหัวข้อ Authorization และหากยังไม่ได้ตั้ง token จะเพิ่มจากพื้นที่เก็บข้อมูล เมื่อได้รับคำตอบ 401, interceptor สามารถรีเฟรช token ผ่าน Authenticator
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 (ConnectionPool) เป็นการเพิ่มประสิทธิภาพหลักของ OkHttp ที่ช่วยให้สามารถใช้การเชื่อมต่อ TCP ซ้ำสำหรับหลายคำขอ แทนที่จะสร้าง socket ใหม่สำหรับแต่ละคำขอ, OkHttp จะเก็บไว้สูงสุด 5 การเชื่อมต่อที่ไม่ใช้งาน (โดยค่าเริ่มต้น) เป็นเวลา 5 นาที ซึ่งช่วยลดความหน่วงลง 30–70% สำหรับคำขอซ้ำไปยังโฮสต์เดียวกัน
การแคชคำตอบนั้นใช้คลาส Cache ในการเปิดใช้งาน caching เพียงระบุไดเร็กทอรีและขนาดสูงสุดใน OkHttpClient.Builder ก็เพียงพอ OkHttp จะแคชคำตอบ GET โดยอัตโนมัติตามหัวข้อ Cache-Control, Expires และ ETag และส่งคืนข้อมูลที่แคชไว้โดยไม่ต้องส่งคำขอไปยังเครือข่ายหากข้อมูลนั้นยังไม่ล้าสมัย
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()
การกำหนดค่า pool และ cache ที่เหมาะสมมีความสำคัญเฉพาะสำหรับ แอพพลิเคชันที่มีคำขอบ่อย — ฟีดข่าว, แชท, การอัพเดตข้อมูล หากไม่มี pool, แต่ละการเชื่อมต่อ TCP ต้องการสามทางให้คำมัน (SYN, SYN-ACK, ACK) และอาจต้องการ TLS handshake (2–3 ราวน์ดทริป) ซึ่งเพิ่ม 100–500 มิลลิวินาทีในแต่ละคำขอ
OkHttp ยังรองรับ WebSocket ผ่านคลาส RealWebSocket การเชื่อมต่อ WebSocket จะถูกสร้างผ่าน HTTP handshake (101 Switching Protocols) และจะเปลี่ยนไปใช้โปรโตคอลสองทาง OkHttp จะส่ง ping frames โดยอัตโนมัติเพื่อรักษาการเชื่อมต่อไว้ และเชื่อมต่อใหม่เมื่อขาดการเชื่อมต่อ WebSocket ของ OkHttp เข้ากันได้กับเอนด์พอยน์มาตรฐานอย่าง wss://echo.websocket.org
การสร้าง OkHttpClient ใหม่ทุกครั้งที่มีคำขอ เป็นข้อผิดพลาดที่พบบ่อยที่สุด OkHttpClient ประกอบด้วย connection pool, cache และ thread pool การสร้างอินสแตนซ์ใหม่สำหรับแต่ละคำขอไม่เพียงแต่สิ้นเปลืองหน่วยความจำ แต่ยังทำให้สูญเสียประโยชน์ของการใช้งานคำขอซ้ำ OkHttpClient ควรเป็น singleton ผ่าน DI container
การละเว้การปิด Response.body() ทำให้เกิดการรั่วไหลทรัพยากร ResponseBody ประกอบด้วย InputStream ที่ต้องปิดหลังจากอ่าน หากใช้ body().string() หรือ body().bytes(), OkHttp จะปิดสตรีมโดยอัตโนมัติ แต่เมื่ออ่าน body().byteStream() หรือ body().charStream() จะต้องมีการเรียก close() อย่างชัดเจนในบล็อก finally
ขาดการจัดการ Timeout เป็นอีกปัญหาหนึ่ง โดยค่าเริ่มต้น OkHttp มี connectTimeout 10 วินาที, readTimeout 10 วินาที และ writeTimeout 10 วินาที สำหรับแอพพลิเคชันมือถือที่มีการเชื่อมต่อไม่มั่นคง แนะนำให้ตั้ง connectTimeout 15–30 วินาที และ readTimeout 15–30 วินาที มิฉะนั้นผู้ใช้จะรอนานเกินไปเมื่อสัญญาณอ่อน
คำถามที่พบบ่อย
OkHttp เป็น HTTP Client ระดับต่ำที่มีการจัดการคำขอและคำตอบด้วยตนเอง Retrofit เป็นการสร้างนามธรรมระดับสูงที่มีคำอธิบาย OkHttp ถูกใช้เป็นขั้นของการส่งต่อสำหรับ Retrofit แต่สามารถทำงานได้อย่างอิสระโดยไม่ต้องใช้ไลบรารีเพิ่มเติม
OkHttp ใช้ SSLSocketFactory สำหรับ TLS handshake ไลบรารีรองรับ CertificatePinner สำหรับการระบุใบรับรอง, TrustManager สำหรับการตรวจสอบแบบกำหนดเอง และ HostnameVerifier สำหรับตรวจสอบชื่อโฮสต์กับใบรับรอง
คำขอแบบซึงโครนัสจะขว้าง IOException เมื่อเกิดปัญหาเครือข่าย คำขอแบบอยต์โครนัสจะได้รับการเรียก onFailure พร้อม IOException สำหรับข้อผิดพลาด HTTP (4xx, 5xx) คำตอบจะถูกถือว่าสำเร็จ — รหัสข้อผิดพลาดจะถูกตรวจสอผ่าน response.isSuccessful()
ใช่ OkHttp มีการรองรับ WebSocket ในตัวผ่านคลาส WebSocket และ WebSocketListener หลังจากสร้างการเชื่อมต่อ, WebSocket จะช่วยให้สามารถส่งและรับข้อความแบบเรียลไทม์โดยไม่ต้องมีคำขอ HTTP ซ้ำ
ปิดการเรียกโอนอัตโนมัติผ่าน followRedirects(false) และ followSslRedirects(false) ใน OkHttpClient.Builder ทำเช่นนี้มีประโยชน์เมื่อคุณต้องการจัดการเรียกโอนด้วยตนเอง ตัวอย่างเช่น เพื่อแยก token จาก URL ของการเรียกโอน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ