Interceptor เป็นส่วนประกอบของ OkHttp และ Alamofire ที่สกัดกั้นคำขอและการตอบกลับ HTTP เพื่อการบันทึกข้อมูล การตรวจสอบสิทธิ์ การแคช และการลองใหม่ ตามข้อมูลจาก Square (2026) ตัวสกัดกั้นที่กำหนดค่าอย่างถูกต้องช่วยลดเวลาในการดีบักเครือข่ายลง 40% และทำให้การจัดการข้อผิดพลาดเป็นมาตรฐาน Application Interceptor ทำงานหนึ่งครั้งต่อคำขอ ในขณะที่ Network Interceptor ทำงานในการเปลี่ยนเส้นทางแต่ละครั้ง
ประเด็นสำคัญ
Interceptor เป็นส่วนประกอบซอฟต์แวร์ที่ถูกฉีดเข้าไปในไคลเอ็นต์ HTTP เพื่อสกัดกั้นและแก้ไขคำขอก่อนที่จะส่งไปยังเซิร์ฟเวอร์และการตอบกลับก่อนที่จะถึงแอปพลิเคชัน ในการพัฒนามือถือ ตัวสกัดกั้นจัดการกับงานที่เกี่ยวข้องข้ามส่วน: การฉีดโทเคนการตรวจสอบสิทธิ์อัตโนมัติ การบันทึกการรับส่งข้อมูลพร้อมการวัดเวลา การลองใหม่เมื่อเกิดข้อผิดพลาดเครือข่ายชั่วคราว การบีบอัดและถอดรหัสข้อมูลแบบทันที สถาปัตยกรรม Interceptor ขึ้นอยู่กับรูปแบบ Chain of Responsibility — ตัวสกัดกั้นแต่ละตัวสามารถแก้ไขคำขอ ดำเนินการ หรือขัดจังหวะห่วงโซ่โดยส่งคืนการตอบกลับที่กำหนดเอง
ใน OkHttp ตัวสกัดกั้นจะสร้างห่วงโซ่ Interceptor แต่ละตัวจะได้รับออบเจ็กต์ Chain พร้อมกับคำขอเดิมและเรียก chain.proceed(request) เพื่อส่งต่อการควบคุมไปยังตัวสกัดกั้นถัดไป หลังจากได้รับการตอบกลับ ตัวสกัดกั้นสามารถวิเคราะห์ Response แก้ไข ลองคำขอใหม่เมื่อเกิดข้อผิดพลาด หรือส่งคืนการตอบกลับที่กำหนดเองสำหรับการแคช ลำดับการเพิ่มตัวสกัดกั้นใน OkHttpClient.Builder กำหนดลำดับการทำงาน: ตัวที่ถูกเพิ่มก่อนจะทำงานก่อนเมื่อส่งและสุดท้ายเมื่อรับ
OkHttp แบ่งตัวสกัดกั้นออกเป็นสองชนิด Application Interceptor (addInterceptor) ทำงานระหว่างโค้ดแอปพลิเคชันและ OkHttp: หนึ่งการเรียก chain.proceed() — หนึ่งคำขอไปยังเซิร์ฟเวอร์ โดยไม่คำนึงถึงการเปลี่ยนเส้นทาง Network Interceptor (addNetworkInterceptor) ทำงานภายใน OkHttp หลังจากการสร้างส่วนหัวและการเชื่อมต่อ — มันจะทำงานในการเปลี่ยนเส้นทาง การลองใหม่ หรือความพยายามตรวจสอบสิทธิ์แต่ละครั้ง ความแตกต่างนี้สำคัญอย่างยิ่งสำหรับการเลือกชนิดตัวสกัดกั้นที่เหมาะสมสำหรับงานเฉพาะ
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
Log.d("HTTP", "${request.method} ${request.url}")
val startTime = System.currentTimeMillis()
val response = chain.proceed(request)
val duration = System.currentTimeMillis() - startTime
Log.d("HTTP", "${response.code} in ${duration}ms")
return response
}
}
val client = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor())
.addNetworkInterceptor(CacheInterceptor())
.build()
LoggingInterceptor — Application Interceptor ที่บันทึกวิธีการ URL รหัสการตอบกลับ และเวลาดำเนินการ การเพิ่มผ่าน addInterceptor() รับประกันหนึ่งบันทึกต่อคำขอผู้ใช้โดยไม่ซ้ำกันในการเปลี่ยนเส้นทาง CacheInterceptor ถูกเพิ่มเป็น Network Interceptor เพื่อพิจารณาส่วนหัว Cache-Control จากเซิร์ฟเวอร์ ซึ่งมองเห็นได้เฉพาะภายใน OkHttp หลังจากการสร้างคำขอ HTTP
เมื่อแอปพลิเคชันทำการขอ เซิร์ฟเวอร์อาจตอบกลับด้วยการเปลี่ยนเส้นทาง 302 หรือ 301 Application Interceptor จะเห็นเฉพาะการตอบกลับสุดท้ายหลังจากการเปลี่ยนเส้นทางทั้งหมด — มันไม่ทราบว่ามีคำขอระหว่างกลางกี่คำขอที่ถูกทำ Network Interceptor จะเห็นทุกคำขอและการตอบกลับ รวมถึงคำขอระหว่างกลาง ตามข้อมูลจาก Square (2026) Network Interceptor ยังเห็นข้อมูลที่ถูกบีบอัดในระดับการเชื่อมต่อ (gzip) ในขณะที่ Application Interceptor ได้รับการตอบกลับที่ถูกคลายการบีบอัดแล้ว ในการนับจำนวนการเรียกเครือข่ายจริง ให้ใช้ Network Interceptor
Alamofire ให้โปรโตคอล RequestInterceptor ซึ่งรวมสองโปรโตคอล: RequestAdapter สำหรับแก้ไขคำขอก่อนส่งและ RequestRetrier สำหรับการลองใหม่เมื่อเกิดข้อผิดพลาด การแยกนี้ช่วยให้สามารถรวมการปรับเปลี่ยน (การเพิ่มส่วนหัว โทเคน) กับนโยบายการลองใหม่ (การหน่วงเวลาแบบเอกซ์โพเนนเชียล จำกัดความพยายาม ตรวจสอบชนิดข้อผิดพลาด) ได้อย่างยืดหยุ่น RequestInterceptor ถูกนำไปใช้โดยโครงสร้างหรือคลาสเดียวที่สอดคล้องกับทั้งสองโปรโตคอล
struct AuthInterceptor: RequestInterceptor {
private let tokenProvider: TokenProvider
func adapt(_ urlRequest: URLRequest,
using state: Session.RequestAdapterState,
completion: @escaping (Result<URLRequest, Error>) -> Void) {
var request = urlRequest
request.setValue("Bearer \(tokenProvider.token)",
forHTTPHeaderField: "Authorization")
completion(.success(request))
}
func retry(_ request: Request,
for session: Session,
dueTo error: Error,
completion: @escaping (RetryResult) -> Void) {
if error is URLError {
completion(.retryWithDelay(1))
} else {
completion(.doNotRetry)
}
}
}
AuthInterceptor บน Swift เพิ่มโทเคน Bearer ผ่าน adapt และลองคำขอใหม่โดยอัตโนมัติเมื่อ URLError (สูญเสียเครือข่าย หมดเวลา) ผ่าน retry ด้วยความหน่วง 1 วินาที การแยกการปรับเปลี่ยนและการลองใหม่ช่วยให้สามารถทดสอบได้อย่างอิสระ — คุณสามารถเขียนการทดสอบหน่วยสำหรับการปรับเปลี่ยนโดยไม่กระทบต่อตรรกะการลองใหม่ ตามข้อมูลจาก Alamofire (2026) RequestInterceptor เป็นวิธีมาตรฐานในการรวมศูนย์การจัดการการตรวจสอบสิทธิ์ในโปรเจกต์ iOS
การบันทึก — กรณีการใช้งานที่พบบ่อยที่สุด Interceptor บันทึก URL วิธีการ ส่วนหัว เนื้อหาคำขอและการตอบกลับ และเวลาดำเนินการ ในบิลด์ดีบัก สิ่งนี้แทนที่ Charles Proxy และ Wireshark; ในบิลด์รีลีส มันช่วยรายงานข้อขัดข้องด้วยบริบทของคำขอ OkHttp ใช้ HttpLoggingInterceptor จากไลบรารี logging-interceptor ด้วยระดับ NONE, BASIC, HEADERS และ BODY ระดับ BODY บันทึกเนื้อหาคำขอและการตอบกลับทั้งหมด — ใช้เฉพาะในดีบักเท่านั้น
เมื่อโทเคนเข้าถึงหมดอายุ Interceptor จะสกัดกั้นการตอบกลับ 401 เรียก API รีเฟรชโทเคน และลองคำขอเดิมอีกครั้งด้วยโทเคนใหม่ ใน OkHttp สิ่งนี้ถูกนำไปใช้ผ่าน Authenticator หรือ Interceptor ที่กำหนดเองพร้อมการตรวจสอบ response.code Authenticator สามารถเข้าถึงได้เฉพาะส่วนหัวของการตอบกลับ ในขณะที่ Interceptor สามารถเข้าถึงเนื้อหาทั้งหมด ใน Alamofire — ผ่าน RequestRetrier ซึ่งส่งคืน .retry หลังจากการรีเฟรชโทเคน ตามข้อมูลจาก OWASP (2026) การรีเฟรชโทเคนอัตโนมัติผ่าน Interceptor ช่วยลดความเสี่ยงของการรั่วไหลของข้อมูลประจำตัว
Content-Type, Accept-Language, User-Agent, Device-ID — ส่วนหัวที่จำเป็นในทุกคำขอ Interceptor เพิ่มสิ่งเหล่านี้จากส่วนกลาง โดยไม่ซ้ำกันในแต่ละวิธีการ API User-Agent ถูกสร้างขึ้นครั้งเดียวเมื่อเริ่มต้นแอป: “AppName/1.0 (Android 14; Pixel 8)” Accept-Language ถูกนำมาจากภาษาระบบของอุปกรณ์ ตามข้อมูลจาก Alamofire (2026) การจัดการส่วนหัวแบบรวมศูนย์ผ่าน Interceptor ช่วยลดข้อผิดพลาดของส่วนหัวที่ไม่ถูกต้องลง 30%
| สถานการณ์ | OkHttp | Alamofire |
|---|---|---|
| การบันทึก | HttpLoggingInterceptor | EventMonitor |
| โทเคนตรวจสอบสิทธิ์ | Authenticator + Interceptor | RequestInterceptor |
| ส่วนหัว | addInterceptor | RequestAdapter |
| การลองใหม่ | Interceptor พร้อมการลองใหม่ | RequestRetrier |
| การแคช | CacheInterceptor | CachedResponseHandler |
ลำดับการเพิ่ม Interceptors ใน OkHttp กำหนดพฤติกรรม ของห่วงโซ่ทั้งหมด ตัวสกัดกั้นที่ถูกเพิ่มก่อนจะทำงานก่อนเมื่อส่งคำขอและสุดท้ายเมื่อได้รับการตอบกลับ สำหรับ การบันทึก ให้เพิ่ม Interceptor ก่อน — มันจะเห็นคำขอสุดท้ายพร้อมการแก้ไขทั้งหมดจากตัวสกัดกั้นอื่น สำหรับ การบีบอัด ให้เพิ่มมันสุดท้ายเพื่อให้การบีบอัดถูกนำไปใช้กับข้อมูลสุดท้าย สำหรับ การตรวจสอบสิทธิ์ ให้เพิ่มมันก่อนการลองใหม่เพื่อให้โทเคนถูกรีเฟรชก่อนความพยายามครั้งถัดไป
ในบิลด์รีลีส ให้ปิดการบันทึกผ่าน BuildConfig.DEBUG หรือการฉีด dependency ใช้ addNetworkInterceptor สำหรับการแคช — Network Interceptor เห็นส่วนหัว Cache-Control ของเซิร์ฟเวอร์และแปลนโยบายการแคชอย่างถูกต้อง สำหรับการตรวจสอบสิทธิ์ ให้ใช้ addInterceptor (Application) — สิ่งนี้ป้องกันการสกัดกั้นซ้ำในการเปลี่ยนเส้นทางไปยังโดเมนของบุคคลที่สามที่ไม่ควรส่งส่วนหัวการอนุญาต ทดสอบ Interceptor แต่ละตัวอย่างแยกกันโดยใช้ MockWebServer จาก okhttp-testing-support — มันสกัดกั้นคำขอและส่งคืนการตอบกลับที่เตรียมไว้ล่วงหน้า ทำให้คุณสามารถตรวจสอบตรรกะของตัวสกัดกั้นโดยไม่ต้องใช้เซิร์ฟเวอร์จริง
Interceptor แต่ละตัวเพิ่มความหน่วงเล็กน้อยให้กับเวลาคำขอ ในห่วงโซ่ทั่วไปของ 3-4 ตัวสกัดกั้น (การบันทึก การตรวจสอบสิทธิ์ การบีบอัด การแคช) ค่าใช้จ่ายเพิ่มเติมน้อยกว่า 5 มิลลิวินาทีต่อคำขอ ปัญหาเกิดขึ้นเมื่อ Interceptor ดำเนินการที่บล็อก: การเรียก API รีเฟรชโทเคนแบบซิงโครนัส การเขียนบันทึกขนาดใหญ่ลงในไฟล์ หรือการเข้ารหัสเนื้อหาคำขอ การดำเนินการทั้งหมดนี้ควรเป็นแบบอะซิงโครนัสหรือดำเนินการในเธรดพื้นหลัง ตามข้อมูลจาก Square (2026) OkHttp ดำเนินการ Interceptors ในพูลเธรด Dispatcher — การบล็อกตัวสกัดกั้นหนึ่งตัวทำให้ทั้งห่วงโซ่ล่าช้า
คำถามที่พบบ่อย
addInterceptor (Application) ทำงานหนึ่งครั้งระหว่างแอปพลิเคชันและ OkHttp — มันไม่เห็นการเปลี่ยนเส้นทางหรือการบีบอัดการเชื่อมต่อ addNetworkInterceptor (Network) ทำงานภายใน OkHttp ในการเรียกเครือข่ายแต่ละครั้ง — มันเห็นการเปลี่ยนเส้นทาง การลองใหม่ และข้อมูลหลังการบีบอัด เลือก Application สำหรับการบันทึกและการตรวจสอบสิทธิ์ Network สำหรับการแคช
ตัวสกัดกั้นตรวจสอบ response.code == 401 เรียก API รีเฟรชโทเคนแบบอะซิงโครนัสผ่าน Retrofit หรือ URLSession บันทึกโทเคนใหม่และลองคำขอเดิมอีกครั้ง ใน OkHttp ให้ใช้ Authenticator สำหรับ Basic Auth และ Interceptor สำหรับ Bearer พร้อมการรีเฟรช ใน Alamofire — ใช้ retry พร้อมการตรวจสอบชนิดข้อผิดพลาด
ใช่ — การดำเนินการหนักใน Interceptor (การบันทึกเนื้อหาขนาดใหญ่ การเข้ารหัส การเรียก API แบบซิงโครนัส) เพิ่มเวลาตอบสนอง ใช้ callback แบบอะซิงโครนัส จำกัดการบันทึกเฉพาะบิลด์ดีบักผ่าน BuildConfig.DEBUG และอย่าดำเนินการที่บล็อกในเมธอด intercept
Authenticator เป็นตัวสกัดกั้นเฉพาะทางสำหรับการตอบกลับ 401 ที่ใช้ Basic Auth หรือ Bearer token Authenticator ไม่สามารถเข้าถึงเนื้อหาคำขอและไม่สามารถแก้ไขส่วนหัวก่อนส่ง — มันจัดการเฉพาะการตอบกลับข้อผิดพลาดการอนุญาต ในทางกลับกัน Interceptor สามารถแก้ไขคำขอในขั้นตอนใดก็ได้ของการดำเนินการ
ใน OkHttp ให้ส่ง Interceptor ไปยัง OkHttpClient.Builder — คำขอทั้งหมดจากไคลเอ็นต์นี้ผ่านมัน ใน Alamofire ให้เพิ่ม RequestInterceptor ในการกำหนดค่า Session หากคุณใช้หลายไคลเอ็นต์ (เช่น สำหรับ API ที่แตกต่างกัน) ให้สร้าง Builder พื้นฐานพร้อมตัวสกัดกั้นทั่วไปโดยใช้รูปแบบ Builder
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม