เลเยอร์เครือข่ายสมัยใหม่ใน iOS โดยใช้ Async/Await

ภาพรวมใหม่ของหัวข้อเครือข่ายที่ใช้ประโยชน์จากโมเดลการทำงานพร้อมกันของ Swift

ฉันต้องสารภาพว่า การสร้างเลเยอร์เครือข่ายเป็นหัวข้อที่น่าตื่นเต้นสำหรับฉันมาโดยตลอด นับตั้งแต่วันแรกของการเขียนโปรแกรม iOS ในต้นปี 2550 โปรเจ็กต์ใหม่แต่ละโปรเจ็กต์แสดงถึงโอกาสใหม่ในการปรับแต่งหรือทำลายแนวทางทั้งหมดที่ฉันเคยใช้มาจนถึงตอนนี้ ความพยายามครั้งสุดท้ายของฉันในการเขียนบางอย่างในหัวข้อนี้ ลงวันที่ปี 2017 และฉันคิดว่านี่เป็นเหตุการณ์สำคัญหลังจากเปลี่ยนมาเป็นภาษา Swift

เป็นเวลานานแล้วตั้งแต่นั้นมา ภาษามีการพัฒนาเหมือนกับกรอบงานระบบ และเมื่อเร็วๆ นี้ ด้วยการเปิดตัว "โมเดลการทำงานพร้อมกันของ Swift" ใหม่ ฉันจึงตัดสินใจก้าวไปอีกขั้นและอัปเดตแนวทางของฉันในเลเยอร์เครือข่าย เวอร์ชันใหม่นี้ได้รับการออกแบบใหม่ครั้งใหญ่ซึ่งช่วยให้คุณสามารถเขียน คำขอ ด้วยโค้ดเพียงบรรทัดเดียว:

ในเวลานี้ คุณอาจกำลังคิดว่า: เหตุใดฉันจึงควรทำให้ลูกค้าของฉันแทนที่จะพึ่งพา Alamofire? คุณพูดถูก การใช้งานใหม่ยังไม่บรรลุนิติภาวะอย่างหลีกเลี่ยงไม่ได้และเป็นสาเหตุของปัญหาในระยะเวลาหนึ่ง แม้ว่าคุณจะมีโอกาสสร้างการผสานรวมที่ได้รับการปรับแต่งกับซอฟต์แวร์ของคุณ และหลีกเลี่ยงการพึ่งพาบุคคลที่สาม นอกจากนี้ คุณยังสามารถใช้ประโยชน์จากเทคโนโลยีใหม่ของ Apple เช่น URLSession, Codable, Async/Await & Actors.
คุณสามารถค้นหาโค้ดได้บน GitHub; โครงการนี้มีชื่อว่า "RealHTTP"

ลูกค้า

เริ่มต้นด้วยการกำหนดประเภทสำหรับการเป็นตัวแทนลูกค้า ไคลเอ็นต์ (เดิมชื่อ HTTPClient) คือโครงสร้างที่มาพร้อมกับคุกกี้ ส่วนหัว ตัวเลือกความปลอดภัย กฎเครื่องมือตรวจสอบ การหมดเวลา และการตั้งค่าที่ใช้ร่วมกันอื่นๆ ทั้งหมดที่คุณอาจมีเหมือนกันระหว่างกลุ่มคำขอ เมื่อคุณเรียกใช้คำขอในไคลเอนต์ คุณสมบัติทั้งหมดเหล่านี้จะมาจากไคลเอนต์โดยอัตโนมัติ เว้นแต่คุณจะปรับแต่งในคำขอเดียว

ตัวอย่างเช่น เมื่อคุณดำเนินการเรียกการตรวจสอบสิทธิ์และรับโทเค็น JWT คุณอาจต้องการตั้งค่าข้อมูลประจำตัวที่ระดับไคลเอ็นต์ ดังนั้นคำขออื่นใดจึงรวมข้อมูลเหล่านี้ไว้ด้วย สิ่งเดียวกันนี้เกิดขึ้นกับเครื่องมือตรวจสอบความถูกต้อง: เพื่อหลีกเลี่ยงการทำซ้ำตรรกะสำหรับการตรวจสอบความถูกต้องของข้อมูล คุณอาจต้องการสร้างเครื่องมือตรวจสอบใหม่และปล่อยให้ไคลเอ็นต์ดำเนินการกับทุกคำขอที่ดึงข้อมูล ลูกค้ายังเป็นตัวเลือกที่ดีเยี่ยมในการใช้กลไกการลองซ้ำซึ่งไม่มีอยู่ในการใช้งาน URLSession พื้นฐาน

คำขอ

ดังที่คุณอาจจินตนาการได้ คำขอ (เดิมคือ HTTPRequest) สรุปการเรียกไปยังปลายทางเพียงครั้งเดียว

หากคุณได้อ่านบทความอื่นๆ ในหัวข้อนี้ คุณอาจพบว่าตัวเลือกทั่วไปคือการใช้ "Swift's Generic" เพื่อจัดการผลลัพธ์ของคำขอ
บางอย่างเช่น: struct HTTPRequest<Response>.

ช่วยให้คุณสามารถเชื่อมโยงประเภทออบเจ็กต์เอาต์พุตกับคำขอได้อย่างมาก แม้ว่าจะเป็นการใช้โครงสร้างที่ยอดเยี่ยมนี้อย่างชาญฉลาด แต่ฉันพบว่ามันทำให้คำขอมีข้อจำกัดเล็กน้อย จากมุมมองเชิงปฏิบัติ คุณอาจจำเป็นต้องใช้ "การลบประเภท" เพื่อจัดการกับวัตถุนี้นอกบริบท นอกจากนี้ ตามแนวคิดแล้ว ฉันชอบที่จะแยกขั้นตอนการร้องขอ (ดึงข้อมูล ~› รับข้อมูลดิบ ~› ถอดรหัสวัตถุ) แยกจากกันและสามารถระบุตัวตนได้ง่าย

ด้วยเหตุผลเหล่านี้ ฉันจึงเลือกที่จะหลีกเลี่ยงยาชื่อสามัญและส่งคืนการตอบสนองดิบ (HTTPResponse) จากคำขอ วัตถุจึงรวมฟังก์ชันทั้งหมดเพื่อให้สามารถถอดรหัสได้ง่าย (เราจะดูด้านล่าง)

กำหนดค่าคำขอ

ดังที่เราได้กล่าวไปแล้ว คำขอจะต้องอนุญาตให้เราตั้งค่าคุณลักษณะที่เกี่ยวข้องทั้งหมดสำหรับการโทรได้อย่างง่ายดาย โดยเฉพาะ “วิธี HTTP” “เส้นทาง” “ตัวแปรแบบสอบถาม” และ “เนื้อหา” นักพัฒนา Swift รักอะไรมากกว่าสิ่งอื่นใด ประเภทความปลอดภัย

ฉันทำมันสำเร็จในสองวิธี: การใช้อ็อบเจ็กต์การกำหนดค่าแทนการใช้ตัวอักษรและโปรโตคอลเพื่อให้การกำหนดค่าที่ขยายได้พร้อมกับชุดฟังก์ชันตัวสร้างที่สร้างไว้ล่วงหน้า

นี่คือตัวอย่างการกำหนดค่าคำขอ:

ตัวอย่างทั่วไปของการดำเนินการด้านความปลอดภัยประเภทคือวิธี HTTP ซึ่งกลายเป็นแจงนับ แต่ยังรวมถึงส่วนหัวที่ได้รับการจัดการโดยใช้วัตถุ HTTPHeader ที่กำหนดเองด้วย ดังนั้นคุณจึงสามารถเขียนข้อความดังต่อไปนี้:

รองรับทั้งการประกาศคีย์ปลอดภัยประเภทและตัวอักษรที่กำหนดเอง

ตัวอย่างที่ดีที่สุดของการใช้โปรโตคอลคือการตั้งค่าเนื้อหาของคำขอ แม้ว่าท้ายที่สุดแล้วมันจะเป็นสตรีมแบบไบนารี แต่ฉันตัดสินใจสร้างโครงสร้างเพื่อเก็บเนื้อหาข้อมูลและเพิ่มชุดวิธีการอรรถประโยชน์เพื่อสร้างโครงสร้างเนื้อหาที่พบบ่อยที่สุด (HTTPBody): รูปแบบหลายส่วน, อ็อบเจ็กต์ที่เข้ารหัส JSON, สตรีมอินพุต, เข้ารหัส URL ร่างกาย ฯลฯ

ผลลัพธ์คือ:

  • อินเทอร์เฟซที่ขยายได้: คุณสามารถสร้างคอนเทนเนอร์เนื้อหาแบบกำหนดเองสำหรับโครงสร้างข้อมูลของคุณเองและตั้งค่าได้โดยตรง เพียงทำให้เป็นไปตามโปรโตคอล HTTPSerializableBody เพื่ออนุญาตให้มีการซีเรียลไลซ์ข้อมูลอัตโนมัติในการสตรีมข้อมูลเมื่อจำเป็น
  • ชุด API ที่ใช้งานง่าย: คุณสามารถสร้างคอนเทนเนอร์เหล่านี้ทั้งหมดได้โดยตรงจากวิธีการคงที่ที่นำเสนอโดย HTTPBody struct

ต่อไปนี้เป็นตัวอย่างของแบบฟอร์มที่มีหลายส่วน:

การสร้างเนื้อหาด้วยออบเจ็กต์ที่เข้ารหัส JSON ก็อยู่ห่างออกไปหนึ่งบรรทัดด้วยโค้ด:

เมื่อคำขอถูกส่งผ่านไปยังไคลเอนต์ URLSessionTask ที่เกี่ยวข้องจะถูกสร้างขึ้นโดยอัตโนมัติ (ในเธรดอื่น) และดังนั้นโฟลว์ URLSession มาตรฐานจึงถูกดำเนินการ ตรรกะพื้นฐานยังคงใช้ URLSessionDelegate (และผู้รับมอบสิทธิ์คนอื่นๆ ในครอบครัว) คุณสามารถค้นหาเพิ่มเติมได้ในคลาส HTTPDataLoader

ดำเนินการตามคำขอ

HTTPClient ใช้ประโยชน์จาก async/await อย่างเต็มที่ โดยส่งคืนการตอบสนองแบบ Raw จากเซิร์ฟเวอร์ การเรียกใช้คำขอนั้นง่ายดาย เพียงเรียกใช้ฟังก์ชัน fetch() ต้องใช้อาร์กิวเมนต์ไคลเอ็นต์ที่เป็นทางเลือก หากไม่ได้ตั้งค่า ระบบจะใช้อินสแตนซ์ singleton HTTPClient เริ่มต้น (หมายความว่าคุกกี้ ส่วนหัว และการตั้งค่าการกำหนดค่าอื่นๆ เกี่ยวข้องกับอินสแตนซ์ที่ใช้ร่วมกันนี้)

ดังนั้นคำขอจะถูกเพิ่มไปยังไคลเอ็นต์ปลายทางและจะดำเนินการแบบอะซิงโครนัสตามการกำหนดค่า ทั้งการทำให้เป็นอนุกรมและดีซีเรียลไลซ์ของสตรีมข้อมูลถูกสร้างขึ้นใน Task อื่น (เพื่อความเรียบง่าย เธรดอื่น) ซึ่งช่วยให้เราสามารถลดปริมาณงานที่ทำใน HTTPClient ได้

การตอบสนอง

การตอบสนองของคำขอเป็นประเภท HTTPResponse; ออบเจ็กต์นี้สรุปทุกสิ่งเกี่ยวกับการดำเนินการ รวมถึงข้อมูลดิบ รหัสสถานะ ข้อผิดพลาดเพิ่มเติม (ได้รับจากเซิร์ฟเวอร์หรือสร้างโดยเครื่องมือตรวจสอบการตอบสนอง) และข้อมูลเมทริกที่ถูกต้องสำหรับวัตถุประสงค์ในการแก้ไขข้อบกพร่องในการรวม

ขั้นตอนต่อไปคือการแปลงการตอบสนองแบบ Raw ให้เป็นออบเจ็กต์ที่ถูกต้อง (มี/ไม่มี DAO) ฟังก์ชัน decode() ช่วยให้คุณสามารถส่งผ่านคลาสอ็อบเจ็กต์เอาต์พุตที่คาดหวังได้ โดยปกติแล้ว จะเป็นออบเจ็กต์ Codable แต่ก็จำเป็นอย่างยิ่งที่จะต้องเปิดใช้งานการถอดรหัสออบเจ็กต์แบบกำหนดเอง ดังนั้นคุณจึงสามารถใช้ออบเจ็กต์ใดก็ได้ที่สอดคล้องกับโปรโตคอล HTTPDecodableResponse โปรโตคอลนี้เพียงกำหนดฟังก์ชันคงที่: static func decode(_ response: HTTPResponse) throws -> Self?

เมื่อใช้ฟังก์ชัน decode() แบบกำหนดเอง คุณสามารถทำทุกอย่างที่คุณต้องการเพื่อให้ได้ผลลัพธ์ที่คาดหวัง ตัวอย่างเช่น ฉันเป็นแฟนตัวยงของ SwiftyJSON ในตอนแรกอาจดูละเอียดกว่า "Codable" เล็กน้อย แต่ยังให้ความยืดหยุ่นมากกว่าในกรณี Edge การจัดการความล้มเหลวที่ดีขึ้น และกระบวนการเปลี่ยนแปลงที่คลุมเครือน้อยกว่า

เนื่องจากโดยส่วนใหญ่แล้ว คุณอาจต้องการเพียงแค่จบลงด้วยออบเจ็กต์ถอดรหัสเอาต์พุต การดำเนินการ fetch() ยังแสดงพารามิเตอร์ถอดรหัสที่เป็นตัวเลือก ดังนั้นคุณจึงสามารถดึงข้อมูลและถอดรหัสได้ในการส่งผ่านครั้งเดียวโดยไม่ต้องผ่านจากการตอบกลับแบบดิบ

ฟังก์ชันสำรอง fetch() นี้รวมทั้งการดึงข้อมูลและถอดรหัสไว้ในฟังก์ชันเดียว คุณอาจพบว่ามีประโยชน์เมื่อคุณไม่จำเป็นต้องรับรายละเอียดภายในของการตอบสนอง แต่เพียงวัตถุที่ถอดรหัสเท่านั้น

ตรวจสอบ/แก้ไขการตอบกลับ

การใช้ไคลเอนต์แบบกำหนดเองและไม่ใช่ไคลเอนต์ที่ใช้ร่วมกันคือการปรับแต่งตรรกะเบื้องหลังการสื่อสารกับตำแหน่งข้อมูลของคุณ ตัวอย่างเช่น เราจะสื่อสารกับปลายทางที่แตกต่างกันสองแห่งด้วยตรรกะที่แตกต่างกัน (โอ้มนุษย์ สภาพแวดล้อมแบบเดิม…) หมายความว่าทั้งผลลัพธ์และข้อผิดพลาดได้รับการจัดการต่างกัน

ตัวอย่างเช่น ระบบเดิมนั้นอยู่ห่างไกลจากระบบที่คล้ายกับ REST และใส่ข้อผิดพลาดไว้ในเนื้อหาของคำขอ อันใหม่ใช้รหัสสถานะ HTTP ที่เป็นประกาย

เพื่อจัดการกับกรณีเหล่านี้และกรณีที่ซับซ้อนมากขึ้น เราได้แนะนำแนวคิดของเครื่องมือตรวจสอบการตอบสนอง ซึ่งคล้ายกับ "เครื่องมือตรวจสอบความถูกต้องของ Express" มาก โดยพื้นฐานแล้ว เครื่องมือตรวจสอบความถูกต้องถูกกำหนดโดยโปรโตคอลและฟังก์ชันที่จัดเตรียมคำขอและการตอบสนองแบบดิบ ช่วยให้คุณสามารถตัดสินใจขั้นตอนต่อไปได้

คุณสามารถปฏิเสธการตอบกลับและโยนข้อผิดพลาด ยอมรับการตอบกลับหรือแก้ไข ลองใหม่ทันทีหรือลองอีกครั้งหลังจากดำเนินการคำขออื่น (นี่คือตัวอย่างสำหรับโทเค็น JWT ที่หมดอายุซึ่งจำเป็นต้องรีเฟรชก่อนที่จะพยายามต่อไปด้วย คำขอเดิม)

เครื่องมือตรวจสอบจะดำเนินการตามลำดับก่อนที่จะส่งการตอบกลับไปยังระดับของแอปพลิเคชัน คุณสามารถกำหนดเครื่องมือตรวจสอบความถูกต้องหลายรายการให้กับไคลเอนต์ได้ และทั้งหมดสามารถเห็นด้วยกับผลลัพธ์สุดท้ายได้ นี่เป็นเวอร์ชันที่เรียบง่ายของมาตรฐาน HTTPResponseValidator:

https://gist.github.com/malcommac/decbd7a0c57218dae2c5b9af6b4af246

คุณสามารถขยาย/กำหนดค่าด้วยลักษณะการทำงานที่แตกต่างกันได้ นอกจากนี้ HTTPAltResponseValidator ยังเป็นตัวตรวจสอบที่ถูกต้องในการใช้ลอจิกการลองใหม่/หลังการโทร เครื่องมือตรวจสอบสามารถส่งคืนการดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้ซึ่งกำหนดโดย HTTPResponseValidatorResult:

  • nextValidator: เพียงส่งหมายเลขอ้างอิงไปยังเครื่องมือตรวจสอบคนถัดไป
  • failChain: หยุดห่วงโซ่และส่งคืนข้อผิดพลาดสำหรับคำขอนั้น
  • retry: ลองคำขอดั้งเดิมอีกครั้งด้วยกลยุทธ์

ลองกลยุทธ์อีกครั้ง

ข้อดีอย่างหนึ่งของ Alamofire คือโครงสร้างพื้นฐานสำหรับการปรับเปลี่ยนและลองคำขออีกครั้ง การปรับใช้ใหม่ด้วยการโทรกลับนั้นไม่ใช่เรื่องง่าย แต่ด้วย async/await มันง่ายกว่ามาก เราต้องการใช้กลยุทธ์การลองใหม่สองประเภท: การลองใหม่อย่างง่ายโดยมีความล่าช้า และวิธีที่ซับซ้อนกว่าเพื่อดำเนินการเรียกสำรองตามด้วยคำขอต้นทาง

กลยุทธ์การลองใหม่ได้รับการจัดการภายใน URLSessionDelegate ซึ่งได้รับการจัดการโดยออบเจ็กต์ภายในแบบกำหนดเองที่เรียกว่า HTTPDataLoader

ต่อไปนี้เป็นเวอร์ชันที่เรียบง่ายเกินไปของตรรกะที่คุณ "สามารถพบได้ที่นี่" (พร้อมกับความคิดเห็น):

หากคุณกำลังคิดที่จะใช้การลองใหม่อัตโนมัติสำหรับปัญหาการเชื่อมต่อ ให้พิจารณาใช้ waitsForConnectivity แทน หากคำขอล้มเหลวเนื่องจากปัญหาเครือข่าย วิธีที่ดีที่สุดคือแจ้งข้อผิดพลาดให้ผู้ใช้ทราบ ด้วย NWPathMonitor คุณยังคงสามารถตรวจสอบการเชื่อมต่อกับเซิร์ฟเวอร์ของคุณและลองอีกครั้งโดยอัตโนมัติ

การดีบัก

การดีบักเป็นสิ่งสำคัญ วิธีมาตรฐานในการแลกเปลี่ยนการโทรผ่านเครือข่ายกับทีมแบ็กเอนด์คือ "cURL" มันไม่จำเป็นต้องมีการแนะนำ มี ส่วนขยาย ทั้งสำหรับ HTTPRequest และ HTTPResponse ซึ่งสร้างคำสั่ง cURL สำหรับ URLRequest พื้นฐาน

ตามหลักการแล้ว คุณควรโทร cURLDescription เมื่อมีการร้องขอ/ตอบกลับ และคุณจะได้รับข้อมูลทั้งหมดโดยอัตโนมัติ รวมถึงการตั้งค่า HTTPClient ของผู้ปกครองด้วย

คุณสมบัติอื่น ๆ

บทความนี้คงจะยาวกว่านี้มาก เราไม่ได้ครอบคลุมหัวข้อต่างๆ เช่น การปักหมุด SSL, ดาวน์โหลดไฟล์ขนาดใหญ่/ดำเนินการต่อ, การเยาะเย้ยคำขอ และการแคช HTTP ขณะนี้ฟีเจอร์ทั้งหมดเหล่านี้ได้รับการติดตั้งและทำงานในโครงการ GitHub ดังนั้นหากคุณสนใจ คุณสามารถดูแหล่งที่มาได้โดยตรง อย่างไรก็ตาม ฉันได้นำแนวทางเดียวกันกับที่คุณเห็นข้างต้นกลับมาใช้ใหม่

การประกอบ API

ในเวลานี้ เราได้สร้างโครงสร้างพื้นฐานเครือข่ายน้ำหนักเบาที่ทันสมัย

แต่แล้วการใช้งาน API ของเราล่ะ

สำหรับแอปขนาดเล็ก สามารถใช้ HTTPClient โดยตรงโดยไม่ต้องสร้างคำจำกัดความ API ได้ แต่โดยทั่วไปเป็นความคิดที่ดีที่จะกำหนด API ที่มีอยู่เพื่อลดความยุ่งเหยิงในโค้ดของคุณและหลีกเลี่ยงข้อผิดพลาดที่อาจเกิดขึ้นเนื่องจากการทำซ้ำ

โดยส่วนตัวแล้ว ฉันไม่ชอบ "แนวทาง Moya",ที่คุณจำลอง API เป็น enum และแต่ละคุณสมบัติมีสวิตช์แยกกัน โดยทั่วไปแล้ว ฉันคิดว่ามันน่าสับสนเพราะคุณมีคุณสมบัติทั้งหมดที่กำหนดค่าคำขอที่กระจัดกระจายและผสมกันในไฟล์เดียว ท้ายที่สุดแล้ว เป็นการยากที่จะอ่านและแก้ไข และเมื่อคุณเพิ่มตำแหน่งข้อมูลใหม่ คุณควรเลื่อนขึ้นและลงผ่านโค้ดอันใหญ่โตนี้

วิธีการของฉันคือการมีวัตถุที่สามารถกำหนดค่า HTTPRequest ที่ถูกต้องพร้อมที่จะส่งผ่านไปยัง HTTPClient สำหรับตัวอย่างนี้ เราจะใช้ MovieDB APIs 🍿 (คุณควรลงทะเบียนสำหรับบัญชีฟรีเพื่อรับคีย์ API ที่ถูกต้อง)

ตอนนี้ลองใช้เลเยอร์เครือข่ายที่เราสร้างขึ้นเป็นตัวอย่างในทางปฏิบัติ เพื่อความเรียบง่าย เราจะพิจารณา API สองรายการ: หนึ่งรายการเพื่อรับภาพยนตร์ที่กำลังเข้าฉาย/ยอดนิยม/ติดอันดับยอดนิยม และอีกรายการหนึ่งสำหรับการค้นหา

ก่อนอื่น เราต้องการใช้เนมสเปซผ่าน enum เพื่อสร้างคอนเทนเนอร์ที่เราจะใส่ทรัพยากรทั้งหมดสำหรับบริบทเฉพาะ ในกรณีของเรา Rankings และ Movies

ทรัพยากรอธิบายบริการเฉพาะที่นำเสนอจากบริการระยะไกล ต้องใช้พารามิเตอร์อินพุตหลายตัวและใช้เพื่อสร้าง HTTPRequest ที่ถูกต้องที่พร้อมที่จะดำเนินการ โปรโตคอลAPIResourceConvertible อธิบายกระบวนการนี้:

Search เป็นแหล่งข้อมูลสำหรับค้นหาภาพยนตร์ภายใน MovieDB ซึ่งสามารถเริ่มต้นได้ด้วยพารามิเตอร์ที่จำเป็น (querystring) และพารามิเตอร์ทางเลือกอื่นๆ อีกสองตัว (release)year และ includeAdults filter

ฟังก์ชัน request() สร้างคำขอที่ถูกต้องตามเอกสาร MovieDB API เราสามารถทำซ้ำขั้นตอนนี้สำหรับแต่ละเรื่องเพื่อสร้างทรัพยากร Lists เพื่อรับรายการอันดับสำหรับภาพยนตร์ upcoming, popular และ topRated เราจะใส่มันลงในเนมสเปซ Rankings:

MoviesPage แสดงถึงอ็อบเจ็กต์ Codable ซึ่งสะท้อนถึงผลลัพธ์ของการเรียก MovieDB แต่ละครั้ง: ด้วยแนวทางนี้ เราได้รับประโยชน์สามประการ:

  • การเรียก API ได้รับการจัดระเบียบในเนมสเปซตามบริบท
  • ทรัพยากรแต่ละรายการจะอธิบายแนวทางที่ปลอดภัยสำหรับการสร้างคำขอระยะไกล
  • แต่ละทรัพยากรมีตรรกะทั้งหมดที่สร้างคำขอ HTTP ที่ถูกต้อง

สิ่งสุดท้าย: เราควรได้รับอนุญาตให้ HTTPClient ดำเนินการเรียก APIResourceConvertible และส่งคืนออบเจ็กต์ประเภทที่ปลอดภัยตามที่อธิบายไว้ มันค่อนข้างง่ายอย่างที่คุณเห็นด้านล่าง:

สุดท้ายนี้ เราจะสร้าง HTTPClient ของเรา:

และเราสามารถดำเนินการโทรของเราได้:

คุณสามารถค้นหาซอร์สโค้ดแบบเต็มสำหรับ "ตัวอย่างที่นี่"

บทสรุป

ขณะนี้ เรามีเลเยอร์เครือข่ายสมัยใหม่ที่ใช้งานง่ายโดยยึดตาม async/await ที่เราสามารถปรับแต่งได้ เราสามารถควบคุมฟังก์ชันการทำงานได้อย่างสมบูรณ์และมีความเข้าใจกลไกของมันอย่างสมบูรณ์

ไลบรารีที่สมบูรณ์สำหรับระบบเครือข่ายเผยแพร่ภายใต้ใบอนุญาต MIT และเรียกว่า "RealHTTP"; เรากำลังรักษาและพัฒนามัน หากคุณชอบบทความนี้ โปรดพิจารณาเพิ่มดาวให้กับโครงการหรือสนับสนุนการพัฒนา



Want to Connect?
Check out my offnotes newsletter here.