Dio คือ HTTP client ที่ทรงพลังสำหรับ Dart และ Flutter พัฒนาโดยวิศวกรชาวจีน Wenda Wang ไลบรารีนี้มี API ขั้นสูงพร้อมรองรับอินเตอร์เซพเตอร์ FormData การอัปโหลดไฟล์ และการยกเลิกคำขอ ตามข้อมูลจาก pub.dev, 2025 Dio เป็น HTTP client ที่ได้รับความนิยมมากที่สุดในระบบนิเวศ Flutter โดยมีดาวบน GitHub มากกว่า 8 พันดวง
ประเด็นสำคัญ
Dio คือไลบรารี HTTP client ที่ทรงพลังสำหรับภาษา Dart ซึ่งใช้กันอย่างแพร่หลายที่สุดในแอปพลิเคชัน Flutter Dio มี API ที่หลากหลายพร้อมรองรับอินเตอร์เซพเตอร์ การกำหนดค่าส่วนกลาง ทรานสฟอร์มเมอร์ FormData การอัปโหลดไฟล์ และการจัดการหมดเวลาที่ยืดหยุ่น ทำให้เป็นตัวเลือกหลักสำหรับการเชื่อมต่อเครือข่ายในชุมชน Flutter
ไลบรารีนี้สร้างขึ้นโดย Wenda Wang ในปี 2018 เพื่อเป็นทางเลือกแทน HttpClient ในตัวของ dart:io ซึ่งขาดคุณสมบัติที่ทันสมัยมากมาย: การกำหนดค่าแบบครบวงจรสำหรับคำขอทั้งหมด อินเตอร์เซพเตอร์ และการทำให้เป็นอนุกรมอัตโนมัติ ภายในปี 2025 Dio แซงหน้าแพ็คเกจ http ของทีม Dart ในด้านความนิยม ครองอันดับหนึ่งในหมู่ HTTP client ในระบบนิเวศ Flutter ตามข้อมูลจาก pub.dev
Dio รองรับอะแดปเตอร์สามตัว: DartNativeAdapter (ค่าเริ่มต้นบน Android, iOS, Desktop), BrowserAdapter (บน Web) และ IOAdapter อะแดปเตอร์จะถูกเลือกโดยอัตโนมัติตามแพลตฟอร์ม Dio ยังมีอินเทอร์เฟซแบบครบวงจรสำหรับทุกแพลตฟอร์ม Flutter — Android, iOS, Web, macOS, Windows และ Linux
สถาปัตยกรรมของ Dio สร้างขึ้นบนห่วงโซ่ตัวจัดการ แต่ละคำขอจะผ่านลำดับของอินเตอร์เซพเตอร์ที่สามารถแก้ไขคำขอ (InterceptorsWrapper.onRequest) การตอบสนอง (onResponse) หรือจัดการข้อผิดพลาด (onError) หลังจากอินเตอร์เซพเตอร์ คำขอจะไปยังทรานสฟอร์มเมอร์ (Transformer) ซึ่งแปลงข้อมูลก่อนส่ง
อินสแตนซ์ของ Dio ถูกกำหนดค่าผ่านออบเจ็กต์ BaseOptions ที่ประกอบด้วย URL พื้นฐาน ส่วนหัวเริ่มต้น การหมดเวลา ประเภทการตอบสนอง (JSON, stream, plain) พารามิเตอร์คำค้นหา และรูปแบบข้อมูล การตั้งค่าเหล่านี้ใช้กับคำขอทั้งหมดแต่สามารถแทนที่ได้ในคำขอเฉพาะ BaseOptions ให้จุดกำหนดค่าเดียวสำหรับทั้งแอปพลิเคชัน ทำให้การเปลี่ยนเอนด์พอยต์หรือการเพิ่มส่วนหัวส่วนกลางทำได้ง่ายขึ้น
แต่ละคำขอใน Dio ส่งคืน Response<T> โดยที่ T คือชนิดข้อมูลหลังจากการประมวลผลของทรานสฟอร์มเมอร์ โดยค่าเริ่มต้น Dio จะแปลงการตอบสนอง JSON เป็น Map<String, dynamic> โดยอัตโนมัติ สำหรับการตอบสนองแบบมีชนิด Dio จะใช้ร่วมกับแพ็คเกจการทำให้เป็นอนุกรม: json_serializable, freezed หรือ built_value Response ประกอบด้วย data, headers, statusCode, requestOptions และข้อมูลเพิ่มเติม
การกำหนดค่าพื้นฐาน สร้างขึ้นผ่าน Dio(BaseOptions) สามารถตั้งค่า baseUrl สำหรับคำขอทั้งหมด connectTimeout และ receiveTimeout ส่วนหัว content-type และ accept รวมถึง queryParameters พารามิเตอร์ทั้งหมดนี้ใช้กับทุกคำขอ ลดความซ้ำซ้อนของโค้ดและรวมศูนย์การจัดการการตั้งค่าเครือข่าย
Dio รองรับสองโหมดการทำให้เป็นอนุกรม: JSON โดยค่าเริ่มต้น (responseType: ResponseType.json) และสตรีมมิ่ง (ResponseType.stream) ในโหมดสตรีม Response.data ส่งคืน ResponseBody ที่สามารถอ่านเป็นส่วนๆ ได้ ซึ่งสะดวกสำหรับไฟล์ที่มีขนาดใหญ่เมื่อไม่ต้องการโหลดทุกอย่างลงในหน่วยความจำ โหมด plain ส่งคืนสตริงดิบโดยไม่มีการแยกวิเคราะห์ JSON อัตโนมัติ
อินเตอร์เซพเตอร์ เป็นกลไกหลักของ Dio ในการสกัดกั้นและแก้ไขคำขอ การตอบสนอง และข้อผิดพลาด พวกมันแทนที่ Interceptor ของ OkHttp และปลั๊กอินของ Ktor อย่างสมบูรณ์ แต่ด้วย API เฉพาะของ Dart และการรองรับอะซิงโครนัสผ่าน Future สามารถเพิ่มอินเตอร์เซพเตอร์ได้ทั้งในการกำหนดค่าส่วนกลางของ Dio และสำหรับคำขอแต่ละรายการ
| เมธอดอินเตอร์เซพเตอร์ | วัตถุประสงค์ | ตัวอย่างการใช้งาน |
|---|---|---|
| onRequest | แก้ไขคำขอก่อนส่ง | เพิ่มโทเค็นการอนุญาต |
| onResponse | จัดการการตอบสนองที่สำเร็จ | แปลง data เป็นออบเจ็กต์ DTO |
| onError | จัดการข้อผิดพลาดของคำขอ | ลองใหม่อัตโนมัติเมื่อ 503 |
LogInterceptor ในตัวจะบันทึกทุกคำขอ: เมธอด, URL, ส่วนหัว, เนื้อหา และเวลาดำเนินการ มีสองโหมด: กระชับ (หนึ่งบรรทัดต่อคำขอ) และเต็ม (ข้อมูลครบถ้วนพร้อมเนื้อหา) LogInterceptor มีประโยชน์อย่างยิ่งในระหว่างการพัฒนา แต่แนะนำให้ปิดใช้งานในบิลด์ที่เผยแพร่ผ่านการนำเข้าแบบมีเงื่อนไขหรือแฟลกส่วนกลาง
อินเตอร์เซพเตอร์แบบกำหนดเองสร้างขึ้นผ่านคลาส InterceptorsWrapper สามารถแทนที่หนึ่ง สอง หรือทั้งสามเมธอด (onRequest, onResponse, onError) Dio ดำเนินการอินเตอร์เซพเตอร์ตามลำดับที่เพิ่มในรายการอินเตอร์เซพเตอร์อย่างเคร่งครัด หากอินเตอร์เซพเตอร์ไม่เรียก handler.next() ห่วงโซ่จะหยุดชะงักและการตอบสนองหรือข้อผิดพลาดจะไม่ถึงแอปพลิเคชัน
สำหรับการพิสูจน์ตัวตนใน Dio จะใช้อินเตอร์เซพเตอร์ที่เพิ่มโทเค็น Bearer ในส่วนหัว Authorization หากเซิร์ฟเวอร์ส่งคืน 401 อินเตอร์เซพเตอร์ใน onError จะพยายามรีเฟรชโทเค็นผ่านคำขอรีเฟรชและทำซ้ำคำขอเดิมด้วยโทเค็นใหม่ รูปแบบนี้เรียกว่า ตัวรีเฟรชโทเค็น และถูกนำไปใช้ผ่าน DioException โดยตรวจสอบ response?.statusCode == 401
Dio รองรับตรรกะการลองใหม่ในตัวผ่านแพ็คเกจ dio_smart_retry หรือ RetryInterceptor แบบกำหนดเอง การลองใหม่สำคัญสำหรับแอปพลิเคชันมือถือ: เมื่อการเชื่อมต่อขาดหายไป 2-3 วินาที Dio จะโยน DioException ด้วยชนิด connectionTimeout หรือ connectionError RetryInterceptor จับข้อยกเว้นนี้และลองใหม่สูงสุด 3 ครั้งด้วยหน่วงเวลาแบบเอกซ์โปเนนเชียล (1วินาที, 2วินาที, 4วินาที) ซึ่งช่วยเพิ่มความน่าเชื่อถือของแอปพลิเคชันในสภาพเครือข่ายที่ไม่เสถียร
มาดูคำขอ GET พื้นฐานผ่าน Dio กัน สร้างอินสแตนซ์ด้วย BaseOptions กำหนด URL พื้นฐานและการหมดเวลา คำขอถูกดำเนินการผ่านเมธอด get() ที่ส่งคืน Response พร้อมข้อมูลในรูปแบบ Map
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['เข้าสู่ระบบ'])
สำหรับคำขอ POST พร้อมเนื้อหา JSON จะส่งออบเจ็กต์ Map หรือ DTO แบบกำหนดเอง Dio จะทำให้ Map เป็นอนุกรมเป็น JSON โดยอัตโนมัติผ่าน jsonEncode สำหรับ DTO แบบมีชนิด จะใช้ตัวเลือก queryParameters ฟิลด์ data หรือ Transformer แบบกำหนดเอง
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['ไอดี'])
อินเตอร์เซพเตอร์ แบบกำหนดเองจะเพิ่มโทเค็น Bearer ให้กับทุกคำขอ เมธอด onRequest จะทำงานก่อนส่ง แก้ไขส่วนหัว เมื่อการตอบสนอง 401 อินเตอร์เซพเตอร์สามารถรีเฟรชโทเค็นและลองทำคำขออีกครั้งผ่านเมธอด dio.fetch(requestOptions)
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
Dio ทำให้ง่ายขึ้น การอัปโหลดไฟล์ผ่าน FormData ในการส่งไฟล์ จะสร้าง MultipartFile จาก File, Bytes หรือ AssetBundle FormData จะตั้งค่าส่วนหัว multipart/form-data โดยอัตโนมัติพร้อมขอบเขตและการเข้ารหัสที่ถูกต้อง Dio รองรับความคืบหน้าการอัปโหลดผ่าน onSendProgress
สำหรับการดาวน์โหลดไฟล์ จะใช้เมธอด download() ซึ่งบันทึกสตรีมข้อมูลลงในไฟล์โดยตรง Dio รองรับการดาวน์โหลดต่อหลังจากถูกขัดจังหวะผ่านส่วนหัว Range ซึ่งมีประโยชน์โดยเฉพาะสำหรับไฟล์ขนาดใหญ่ ความคืบหน้าการดาวน์โหลด ถูกติดตามผ่าน onReceiveProgress ทำให้สามารถแสดงแถบความคืบหน้าในอินเทอร์เฟซผู้ใช้
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('อัปโหลด: $progress%')
},
)
// ดาวน์โหลดไฟล์
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('ดาวน์โหลด: ${received / total * 100}%')
},
)
การจัดการข้อผิดพลาดที่ไม่ถูกต้อง เป็นปัญหาที่พบบ่อยที่สุด Dio จะโยน DioException (เดิมคือ DioError) สำหรับปัญหาใดๆ: เครือข่ายไม่พร้อมใช้งาน หมดเวลา ข้อผิดพลาด HTTP 4xx/5xx นักพัฒนาหลายคนจับเฉพาะ Exception ทั่วไป ทำให้สูญเสียข้อมูลเกี่ยวกับชนิดข้อผิดพลาดและความสามารถในการจัดการอย่างเฉพาะเจาะจง ใช้ DioException.type เพื่อระบุสาเหตุของความล้มเหลว
การไม่สนใจ CancelToken นำไปสู่การรั่วไหลของคำขอ หากผู้ใช้ออกจากหน้าจอในขณะที่คำขอยังคงทำงานอยู่ Dio จะสิ้นเปลืองทรัพยากรและอาจพยายามอัปเดต State ที่ถูกทำลาย สร้าง CancelToken สำหรับทุกคำขอเสมอและยกเลิกใน dispose() CancelToken สร้าง DioException ด้วยชนิด cancel ซึ่งต้องได้รับการจัดการอย่างถูกต้อง
ขาดตรรกะการลองใหม่ สำหรับความล้มเหลวชั่วคราว บนอุปกรณ์มือถือ เครือข่ายมักไม่พร้อมใช้งานในช่วงสั้นๆ ใช้อินเตอร์เซพเตอร์กับการลองใหม่คำขออัตโนมัติเมื่อหมดเวลาหรือการตอบสนอง 503/502 ใช้ RetryInterceptor จากแพ็คเกจ dio_smart_retry หรือเขียนอินเตอร์เซพเตอร์แบบกำหนดเองด้วยหน่วงเวลาแบบเอกซ์โปเนนเชียลระหว่างการลอง
คำถามที่พบบ่อย
Dio มีอินเตอร์เซพเตอร์ การกำหนดค่า BaseOptions ส่วนกลาง FormData ความคืบหน้าการอัปโหลด และ CancelToken แพ็คเกจ http จากทีม Dart มีความเรียบง่าย ไม่มีอินเตอร์เซพเตอร์หรือการกำหนดค่าส่วนกลาง Dio ใช้ในโปรเจกต์ขนาดใหญ่ ในขณะที่ http ใช้สำหรับสคริปต์ง่ายๆ
โดยค่าเริ่มต้น Dio จะแปลง JSON เป็น Map โดยใช้ jsonDecode สำหรับการทำให้เป็นอนุกรมแบบมีชนิด ให้ใช้แพ็คเกจ json_serializable หรือ freezed สร้างอินเตอร์เซพเตอร์แบบกำหนดเองที่แปลง response.data เป็น DTO ผ่าน fromJson() ใน onResponse
สร้าง CancelToken และส่งต่อไปในตัวเลือกคำขอ การเรียก token.cancel() จะขัดจังหวะคำขอและโยน DioException ด้วยชนิด cancel CancelToken รองรับการยกเลิกหลายคำขอพร้อมกัน ซึ่งสะดวกสำหรับการยกเลิกคำขอทั้งหมดเมื่อออกจากหน้าจอ
ใช่ Dio ทำงานบนทั้งหกแพลตฟอร์ม Flutter: Android, iOS, Web, macOS, Windows และ Linux แต่ละแพลตฟอร์มใช้ HTTP client ที่ปรับเปลี่ยนได้: DartNativeAdapter (แพลตฟอร์มดั้งเดิม) และ BrowserAdapter (Web) API ที่เป็นหนึ่งเดียวสำหรับทุกแพลตฟอร์มเป็นข้อได้เปรียบหลักของ Dio ในโปรเจกต์ Flutter
Dio ไม่จัดการคุกกี้โดยอัตโนมัติ สำหรับการรองรับคุกกี้ ให้ใช้แพ็คเกจ dio_cookie_manager ร่วมกับ cookie_jar CookieManager จะสกัดกั้นส่วนหัว Set-Cookie และ Cookie และบันทึกคุกกี้ใน PersistCookieJar สำหรับการส่งอัตโนมัติในคำขอถัดไปไปยังโดเมนเดียวกัน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม