ฉันควรใช้รหัสสถานะ HTTP เพื่ออธิบายเหตุการณ์ระดับแอปพลิเคชัน


54

เซิร์ฟเวอร์จำนวนมากที่ฉันจัดการจะส่งคืน HTTP 200 สำหรับคำขอที่ลูกค้าควรพิจารณาถึงความล้มเหลวโดยมี 'ความสำเร็จ: เท็จ' ในเนื้อความ

ดูเหมือนว่าฉันจะใช้รหัส HTTP ไม่ถูกต้องกับฉันโดยเฉพาะในกรณีของการตรวจสอบสิทธิ์ที่ล้มเหลว ฉันได้อ่านรหัสข้อผิดพลาด HTTP โดยสังเขปแล้วสรุปว่า '4xx' บ่งชี้ว่าไม่ควรทำคำขออีกครั้งจนกว่าจะมีการเปลี่ยนแปลงในขณะที่ '5xx' แสดงว่าคำขอนั้นอาจจะใช้งานได้หรืออาจไม่ถูกต้อง แต่ก็ไม่สำเร็จ ในกรณีนี้ 200: การเข้าสู่ระบบล้มเหลวหรือ 200: ไม่พบไฟล์นั้นหรือ 200: พารามิเตอร์ที่หายไป x ดูเหมือนผิดปกติ

ในทางกลับกันฉันเห็นการโต้แย้งว่า '4xx' ควรระบุปัญหาเชิงโครงสร้างของคำขอเท่านั้น ดังนั้นจึงเหมาะสมที่จะส่งคืน 200: ผู้ใช้ / รหัสผ่านไม่ดีแทนที่จะได้รับอนุญาต 401 เนื่องจากลูกค้าได้รับอนุญาตให้ทำการร้องขอ แต่มันเกิดขึ้นไม่ถูกต้อง อาร์กิวเมนต์นี้สามารถสรุปได้ว่าหากเซิร์ฟเวอร์สามารถประมวลผลคำขอและตัดสินใจได้ทั้งหมดรหัสการตอบสนองควรเป็น 200 และขึ้นอยู่กับลูกค้าที่จะตรวจสอบเนื้อหาสำหรับข้อมูลเพิ่มเติม

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


9
success: falseแสดงว่าคำขอล้มเหลวและคุณทราบ นั่นควรเป็น 500 บางอย่างเช่นชื่อผู้ใช้ / รหัสผ่านที่ไม่ดีของคุณจะเป็น 401 สิ่งนี้ไม่ได้คลุมเครือ
Pete


4
นี่เป็นหนึ่งในคำถามที่สามารถก่อให้เกิดสงครามศาสนาที่ฉันคิด สำหรับ RESTful API คำตอบนั้นชัดเจน แต่มี API ประเภทอื่น ๆ ที่ HTTP ได้รับการปฏิบัติเช่นเดียวกับเลเยอร์การส่งผ่านและในกรณีเหล่านั้นข้อผิดพลาดของแอปพลิเคชันไม่ควรตกไปที่เลเยอร์นั้น
Gort the Robot

5
เมื่อฉันไม่แน่ใจจริงๆว่าสถานะ http ใดที่จะส่งคืนจะดึงดูดด้วย 418 "ฉันเป็นกาน้ำชา"
joshp

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

คำตอบ:


35

คำถามที่น่าสนใจ

โดยทั่วไปเราสามารถลดสิ่งนี้ลงไปในวิธีที่ถูกต้องในการจำแนกสิ่งต่าง ๆ ในแง่คล้ายกับชั้น OSI HTTP มักถูกกำหนดให้เป็นโปรโตคอลระดับแอปพลิเคชันและ HTTP เป็นโปรโตคอลไคลเอนต์ / เซิร์ฟเวอร์ทั่วไป

อย่างไรก็ตามในทางปฏิบัติเซิร์ฟเวอร์มักจะเป็นอุปกรณ์ถ่ายทอดสัญญาณและไคลเอนต์เป็นเว็บเบราว์เซอร์รับผิดชอบในการตีความและการแสดงผลเนื้อหา: เซิร์ฟเวอร์เพิ่งส่งสิ่งต่าง ๆ ไปยังแอปพลิเคชันโดยพลการ รับผิดชอบในการดำเนินการ การโต้ตอบ HTTP เอง - ฟอร์มคำขอ / ตอบกลับรหัสสถานะและอื่น ๆ - ส่วนใหญ่เป็นเรื่องของวิธีการร้องขอแสดงและแสดงเนื้อหาตามอำเภอใจอย่างมีประสิทธิภาพมากที่สุดโดยไม่ต้องเดินทาง รหัสสถานะและส่วนหัวจำนวนมากได้รับการออกแบบมาเพื่อวัตถุประสงค์เหล่านี้

ปัญหาเกี่ยวกับการพยายามย้อนกลับโปรโตคอล HTTP สำหรับจัดการโฟลว์เฉพาะแอปพลิเคชันคือคุณเหลือตัวเลือกหนึ่งในสองตัวเลือก: 1) คุณต้องทำให้ตรรกะการร้องขอ / ตอบกลับเป็นส่วนหนึ่งของกฎ HTTP; หรือ 2) คุณต้องนำกฎบางอย่างมาใช้ใหม่อีกครั้งจากนั้นการแยกข้อกังวลมีแนวโน้มที่จะคลุมเครือ สิ่งนี้ดูดีและสะอาดในตอนแรก แต่ฉันคิดว่านี่เป็นหนึ่งในการตัดสินใจออกแบบที่คุณต้องเสียใจเมื่อโครงการของคุณพัฒนา

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

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


8
ลึกซึ้งมาก อาร์กิวเมนต์ที่แข็งแกร่งที่สุดในที่นี้คือ (ความต้านทาน) ไม่ตรงกันระหว่างรหัสสถานะ HTTP และค่าส่งคืนของแอปของคุณ นี่อาจกลายเป็นฝันร้ายในระยะยาว นอกจากนี้ฉันสนับสนุนอย่างมากในการแยกข้อกังวลระหว่าง transport (HTTP) และ payload (ข้อมูลแอป) หากคุณพิมพ์ URL ของจุดสิ้นสุดบริการคุณจะได้รับ 404 หากคุณขอบริการสำหรับรายการที่ไม่มีอยู่คุณจะได้รับข้อความเฉพาะแอป (อาจมีข้อมูลเพิ่มเติมที่คุณสามารถใช้เพื่อแก้ไขปัญหา)

2
หากคุณพิมพ์ URL ผิดคุณอาจไม่ได้ลงทะเบียนที่เซิร์ฟเวอร์ด้านขวาจากนั้นอาจมีสิ่งใดเกิดขึ้น
gnasher729

นี่คือรูปลักษณ์ที่เหมาะสมยิ่ง ฉันคิดว่าปัญหาของ HTTP ที่กลายเป็นเลเยอร์หลอกขนส่งเป็นปัญหาจริงกับการตัดสินใจ ฉันมักจะพบคำถามนี้ด้วยตัวเองเมื่อคุณมีเซิร์ฟเวอร์ nginx หรือ apache proxying เซิร์ฟเวอร์ nodejs ซึ่งพร็อกซีมีกฎอยู่แล้วสำหรับการส่งรหัสเหล่านี้และคำถามกลายเป็นว่ามันเหมาะสมสำหรับแบ็กเอนด์ให้สอดคล้องกับมาตรฐาน ในบางกรณีอาจมีสาเหตุการออกแบบที่จะไม่ส่งรหัสข้อผิดพลาดเนื่องจาก nginx อาจตีความว่าเป็น 'แบ็กเอนด์ลง'
Kagan Mattson

4
ฉันเห็นด้วย. ไม่มีอะไรผิดปกติกับข้อผิดพลาดของแอปพลิเคชันเลเยอร์ที่มีการรายงานในการตอบสนอง HTTP 200 200 บ่งชี้ว่าคำร้องขอ / ตอบกลับ HTTP นั้นสำเร็จโดยไม่ต้องพูดอะไรเกี่ยวกับเนื้อหาหรือซีแมนทิกส์ของเลเยอร์แอปพลิเคชันที่ถูกเรียกใช้ในเวลานั้น
การแข่งขัน Lightness กับ Monica

22

คำถามนี้เป็นความเห็นเล็กน้อยตาม แต่อย่างใด

วิธีที่ฉันเห็นมัน 200 สามารถให้บริการ "ข้อผิดพลาดอ่อน" เมื่อพูดถึงการสร้าง API ฉันพยายามแยกแยะระหว่างสิ่งเหล่านี้กับ "ข้อผิดพลาดอย่างหนัก"

ข้อผิดพลาด "ซอฟท์"จะได้รับบริการที่มีรหัสสถานะของ 200 falseแต่จะมีคำอธิบายข้อผิดพลาดและสถานะความสำเร็จของ "ข้อผิดพลาดที่อ่อนนุ่ม" จะเกิดขึ้นก็ต่อเมื่อผลลัพธ์เป็น "ตามที่คาดหวัง" แต่จะไม่ประสบความสำเร็จในแง่ที่เข้มงวดที่สุด

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

ตัวอย่างเช่นสมมติว่าคุณมี API พร้อมฟังก์ชันการค้นหา แต่ในระหว่างการค้นหาจะไม่มีการให้ผลลัพธ์ นี่ไม่ใช่ข้อผิดพลาด แต่ไม่ใช่ "ความสำเร็จ" เช่นกันไม่ได้อยู่ในความหมายที่เข้มงวดที่สุด

ตัวอย่างที่จัดรูปแบบเป็น JSON:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

"ข้อผิดพลาดอย่างหนัก"ในอีกทางหนึ่งจะได้รับรหัสสถานะซึ่งแนะนำสำหรับข้อผิดพลาดนั้น ผู้ใช้ไม่ได้เข้าสู่ระบบ? - 403/401 อินพุตที่มีรูปแบบไม่ถูกต้อง? - 400. เซิร์ฟเวอร์ผิดพลาด - 50X และอื่น ๆ

อีกครั้งมันเป็นบิตตามความคิดเห็น บางคนต้องการปฏิบัติต่อข้อผิดพลาดทั้งหมดอย่างเท่าเทียมกันทุกอย่าง "ข้อผิดพลาดอย่างหนัก" ไม่มีผลการค้นหา? นั่นคือ 404! ในอีกด้านหนึ่งของเหรียญไม่มีผลการค้นหา? - นี่เป็นไปตามที่คาดไว้ไม่มีข้อผิดพลาด

อีกปัจจัยที่สำคัญที่ต้องพิจารณาคือสถาปัตยกรรมของคุณตัวอย่างเช่น หากคุณโต้ตอบกับ API ของคุณโดยใช้คำขอ JavaScript XHR และ jQuery หรือ AngularJS "ข้อผิดพลาดที่ยาก" เหล่านี้จะต้องได้รับการจัดการด้วยการเรียกกลับแยกต่างหากในขณะที่ "ข้อผิดพลาดที่อ่อน" สามารถจัดการได้ด้วย "สำเร็จ" -callback ไม่ทำลายอะไรเลยผลลัพธ์ยังคงเป็น "ตามคาด" รหัสฝั่งไคลเอ็นต์อาจดูที่สถานะความสำเร็จและรหัส (หรือข้อความ) และพิมพ์ไปยังผู้ใช้ปลายทาง


2
ที่จริงแล้วการจำแนกว่าเป็นข้อผิดพลาดในระดับ API เลยเป็นการตัดสินใจที่อยากรู้อยากเห็น แม้ว่าลูกค้าอาจจำแนกประเภทตามที่ผู้ใช้คาดการณ์ไว้
Deduplicator

1
มีหลายสิ่งที่จะต้องมีการแยกตัวประกอบมันทั้งหมดขึ้นอยู่กับการดำเนินการตาม API นอกจากนี้ยังเป็นไปตามความเห็นเล็กน้อยและยังเป็นสิ่งที่ API กำหนดว่า "สำเร็จ" และ / หรือ "ข้อผิดพลาด" "success": false-flag เป็นมากกว่าคำใบ้ที่จะ implementer ที่บางสิ่งบางอย่างขึ้น โดยปกติควรใช้รหัสสถานะภายใน ไม่ว่าจะ"code": "NORESULTS"เป็นรหัสหรือตัวเลข - ไม่ว่าผู้สร้าง API แบบใดก็ตาม ส่วนใหญ่จะอยู่ที่นั่นดังนั้นใครก็ตามที่ใช้ API สามารถหักข้อมูลเกี่ยวกับสิ่งที่เกิดขึ้นบนเซิร์ฟเวอร์
die maus

15

API มีสองด้าน: ความพยายามในการใช้ API และความพยายามของลูกค้าทั้งหมดในการใช้ API อย่างถูกต้อง

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

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

หากลูกค้าขอให้ "ให้ฉันบันทึกทั้งหมดเช่น ... " และมีศูนย์แล้ว 200 ที่ประสบความสำเร็จและอาร์เรย์ของศูนย์บันทึกมีความเหมาะสมอย่างเต็มที่ กรณีที่คุณพูดถึง:

"การเข้าสู่ระบบล้มเหลว" โดยปกติควรเป็น 401 "ไม่สามารถหาไฟล์" ควรเป็น 404 "พารามิเตอร์ที่หายไป x" ควรมีค่าประมาณ 500 (จริง ๆ แล้ว 400 ถ้าเซิร์ฟเวอร์คิดว่าคำขอไม่ดีและ 500 หากเซิร์ฟเวอร์สับสนโดยสิ้นเชิงจากคำขอของฉันและไม่รู้ว่าเกิดอะไรขึ้น) การส่งคืน 200 ในกรณีเหล่านี้ไม่มีจุดหมาย มันหมายถึงว่าในฐานะผู้เขียนลูกค้าฉันไม่สามารถดูรหัสสถานะได้ฉันต้องศึกษาคำตอบด้วย ฉันไม่สามารถพูดว่า "สถานะ 200 เยี่ยมยอดนี่คือข้อมูล"

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

ในท้ายที่สุดมีรหัสสถานะเป็นโหลหรือสองรหัสสำหรับจัดการสถานการณ์ที่แตกต่างกันมากมายและคุณควรใช้รหัสดังกล่าว


3
เมื่อเชื่อมต่อกับ API ส่วนตัวแล้วฉันจะได้รับ 200 ใน 'file not found' เมื่อเชื่อมต่อกับจุดปลายที่ถูกต้องเนื่องจากการจัดการ HTTP ของฉันไม่จำเป็นต้องมีเลเยอร์ที่จัดการกับ API ที่อยู่ด้านบน
whatsisname

4
"พารามิเตอร์ที่หายไป x" ควรเป็น 400 BAD_REQUEST เพราะเป็นไคลเอนต์ที่ทำสิ่งผิดปกติ 500 INTERNAL_SERVER_ERROR ควรสำรองไว้สำหรับกรณีที่เซิร์ฟเวอร์กำลังทำสิ่งผิด 500 หมายถึงว่าลูกค้าอาจจะสามารถลองอีกครั้ง 400 หมายความว่ามีคนไปแก้ไขลูกค้า
Gort the Robot

1
หากคุณกำลังเขียนอินเตอร์เฟส RESTful URL จะระบุวัตถุเฉพาะดังนั้น 404 จึงเหมาะสม มันเป็นแนวคิดเดียวกัน/customers/premium/johndoe.jsonหมายถึงลูกค้าที่ไม่ได้อยู่ในฐานข้อมูลและหาก/files/morefiles/customers.htmlอ้างถึงหน้าไม่ได้อยู่ในระบบไฟล์
Gort the Robot

@whatsisname สิ่งที่คุณพูดมีเหตุผลเพราะมันไม่ชัดเจนหากเป็นจุดสิ้นสุดที่ไม่ดีหรือไม่มีทรัพยากรอยู่ คุณยังสามารถยืนยันได้ว่าปลายทางนั้นถูกต้องหรือไม่ไม่มีทรัพยากรอยู่ในที่อยู่นั้นดังนั้น a 404จึงถูกต้องในทั้งสองกรณี
Pete

2
สิ่งหนึ่งที่ฉันไม่ได้กล่าวถึงคือเมื่อคุณ piggyback ข้อผิดพลาดของแอปพลิเคชันลงในรหัสสถานะ HTTP คุณอาจสูญเสียข้อมูล หากแอปส่งคืน 404 และไม่มีอะไรเลยคุณไม่ทราบว่าเป็นเพราะ API ของคุณคืน 404 หรือเพราะเซิร์ฟเวอร์หาไฟล์ไม่พบ ซึ่งสามารถเพิ่มหนึ่งขั้นตอนพิเศษในการแก้ไขข้อบกพร่องของคุณ
AmadeusDrZaius
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.