HTTP POST พร้อมพารามิเตอร์การสืบค้น URL - เป็นความคิดที่ดีหรือไม่? [ปิด]


451

ฉันกำลังออกแบบ API ให้ใช้งาน HTTP และฉันสงสัยว่าถ้าใช้คำสั่ง HTTP POST แต่ด้วยพารามิเตอร์การสืบค้น URL เท่านั้นและไม่มีเนื้อหาคำขอเป็นวิธีที่ดี

การพิจารณา:

  • "การออกแบบเว็บที่ดี" ต้องมีการดำเนินการที่ไม่ใช่ idempotent ผ่านทาง POST นี่คือการกระทำที่ไม่ใช่ idempotent
  • การพัฒนาและแก้ไขข้อบกพร่องของแอปนี้ง่ายขึ้นเมื่อมีพารามิเตอร์คำขออยู่ใน URL
  • API ไม่ได้มีไว้สำหรับใช้อย่างแพร่หลาย
  • ดูเหมือนว่าการร้องขอ POST โดยไม่มีเนื้อหาจะทำงานได้อีกเล็กน้อยเช่นContent-Length: 0ส่วนหัวจะต้องเพิ่มอย่างชัดเจน
  • สำหรับฉันแล้วดูเหมือนว่า POST ที่ไม่มีร่างกายนั้นนับว่าตอบสนองต่อความคาดหวังของนักพัฒนาและ HTTP Framework ส่วนใหญ่

มีข้อผิดพลาดหรือข้อได้เปรียบเพิ่มเติมอีกหรือไม่ในการส่งพารามิเตอร์ในคำขอ POST ผ่านการสืบค้น URL แทนที่จะเป็นเนื้อหาคำขอ

แก้ไข: เหตุผลที่อยู่ระหว่างการพิจารณาคือการดำเนินการไม่ใช่ idempotent และมีผลข้างเคียงอื่นนอกเหนือจากการดึงข้อมูล ดูข้อมูลจำเพาะ HTTP :

โดยเฉพาะอย่างยิ่งการประชุมได้รับการจัดตั้งขึ้นว่าวิธีการ GET และหัวไม่ควรมีความสำคัญของการดำเนินการอื่นนอกเหนือจากการดึง วิธีการเหล่านี้ควรได้รับการพิจารณาว่า "ปลอดภัย" สิ่งนี้อนุญาตให้ตัวแทนผู้ใช้แสดงวิธีอื่น ๆ เช่น POST, PUT และ DELETE ในวิธีพิเศษเพื่อให้ผู้ใช้ทราบถึงความจริงที่ว่ามีการร้องขอการดำเนินการที่ไม่ปลอดภัย

...

เมธอดยังสามารถมีคุณสมบัติของ "idempotence" ในนั้น (นอกเหนือจากข้อผิดพลาดหรือปัญหาการหมดอายุ) ผลข้างเคียงของ N> 0 คำร้องขอเหมือนกันนั้นเหมือนกับสำหรับคำร้องขอเดียว เมธอด GET, HEAD, PUT และ DELETE แบ่งปันคุณสมบัตินี้ นอกจากนี้ตัวเลือกวิธีการและการติดตามไม่ควรมีผลข้างเคียงและดังนั้น idempotent โดยเนื้อแท้


11
ทำไมต้องใช้ POST เลยถ้าคุณไม่ให้ข้อมูลในร่างกาย
30826 Sunny Milenov

114
เพราะการดำเนินการไม่ใช่ idempotent
Steven Huwig

20
@Jared โปรดสังเกตว่าคำว่า "REST" ไม่ปรากฏในคำถามนี้เมื่อ 2.5 ปีที่แล้ว :) ข้อมูลจำเพาะเกี่ยวกับ idempotence ของ HTTP นั้นใช้โดยไม่คำนึงถึงสถาปัตยกรรมที่มีกลิ่นอายของเดือนสำหรับบริการเว็บ โชคดีที่ระบบที่ API นี้ออกแบบมาเพื่อใช้งานกับพรอกซีนั้นได้ล้าสมัยไปแล้ว
Steven Huwig

5
เนื่องจากบันทึกเซิร์ฟเวอร์ไม่ได้บันทึกพารามิเตอร์ POST แต่บันทึกสตริงการสืบค้น การเรียกใช้ชุดคำขอได้ง่ายกว่าโดยไม่ต้องใช้เครื่องมือในเบราว์เซอร์จากนั้นดูที่การสืบค้นกลับมากกว่าที่จะคลิกผ่านคำขอเหล่านั้น API ไม่ใช่เบราว์เซอร์ต่อเซิร์ฟเวอร์ แต่เป็นเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ สิ่งสำคัญที่สุดคือเรื่องทั้งหมดถูกกระป๋องอยู่แล้ว :)
Steven Huwig

13
สำหรับคนอื่น ๆ ที่ไม่ทราบว่า idempotent หมายถึงอะไร: | restapitutorial.com/lessons/idempotency.html
คริสโต Grigg

คำตอบ:


259

ถ้าการกระทำของคุณจะไม่ idempotent แล้วคุณจะต้องPOSTใช้ หากคุณไม่ทำคุณแค่ขอให้มีปัญหา GET, PUTและDELETEวิธีการที่จำเป็นที่จะ idempotent ลองนึกภาพสิ่งที่จะเกิดขึ้นในแอปพลิเคชันของคุณหากลูกค้าได้รับGETคำขอล่วงหน้าทุกครั้งที่เป็นไปได้สำหรับบริการของคุณ - หากสิ่งนี้จะทำให้ลูกค้าเห็นผลข้างเคียง

ฉันยอมรับว่าการส่งPOSTสตริงข้อความค้นหา แต่ไม่มีเนื้อความนั้นดูแปลก แต่ฉันคิดว่ามันเหมาะสมในบางสถานการณ์

คิดว่าส่วนแบบสอบถามของ URL เป็นคำสั่งไปยังทรัพยากรเพื่อ จำกัด ขอบเขตของคำขอปัจจุบัน โดยทั่วไปแล้วสตริงแบบสอบถามจะใช้ในการเรียงลำดับหรือกรองGETคำขอ (เช่น?page=1&sort=title) แต่ฉันคิดว่ามันสมเหตุสมผลที่POSTจะ จำกัด ขอบเขต (อาจจะชอบ?action=delete&id=5)


4
ฉันเลือกคำตอบนี้สำหรับกรณีนี้โดยเฉพาะ แต่ฉันคิดว่าอาร์กิวเมนต์ของ R. Bemrose นั้นน่าสนใจสำหรับ API สาธารณะ
Steven Huwig

4
ฉันไม่คิดว่าคำตอบของเขาถูกต้องอย่างเคร่งครัด หากคุณทราบพารามิเตอร์ URL สำหรับการโพสต์แบบฟอร์มของคุณเมื่อหน้า HTML ถูกส่งไปยังลูกค้าคุณสามารถตรึงพารามิเตอร์ URL เหล่านั้นไว้ในแอตทริบิวต์การทำงานของแบบฟอร์มมิฉะนั้น JavaScript สามารถตั้งค่าพารามิเตอร์ URL เมื่อส่งแบบฟอร์ม
Don McCaughey

3
วิธีการเกี่ยวกับการโพสต์ของไฟล์ xml ไปยัง URL ที่มีพารามิเตอร์แบบสอบถาม เป็นไปได้ไหม
OpenCoderX

3
อีกตัวอย่างหนึ่ง: ข้อมูลการร้องขออาจจะอยู่ใน http นิติบุคคลในขณะที่รูปแบบที่ร้องขอของการตอบสนองจะถูกส่งในพารามิเตอร์การค้นหา ( /action?response_format=json)
RDS

4
+1 เรียนรู้บางอย่างวันนี้ การลบมีเทคนิคในการเป็น idempotent หากวัตถุถูกลบจริง ๆ แล้วคุณจะไม่ได้รับ 404 ดังนั้นเซิร์ฟเวอร์จะมีสถานะเดียวกัน แต่การตอบสนองจะแตกต่างกัน ดูรูปวัว: restapitutorial.com/lessons/idempotency.html
JPK

131

ทุกคนถูกต้อง: ติดกับ POST สำหรับคำขอที่ไม่ใช่ idempotent

สิ่งที่เกี่ยวกับการใช้ทั้งสตริงแบบสอบถาม URI และขอเนื้อหา? มันเป็น HTTP ที่ถูกต้อง (ดูหมายเหตุ 1) ดังนั้นทำไมไม่!

นอกจากนี้ยังเป็นเหตุผลอย่างสมบูรณ์: URL รวมถึงส่วนสตริงแบบสอบถามของพวกเขาสำหรับการค้นหาทรัพยากร โดยที่เมธอด HTTP เมธอด (POST - และเนื้อหาคำร้องขอทางเลือก) ใช้สำหรับระบุการดำเนินการหรือสิ่งที่ต้องทำกับรีซอร์ส สิ่งเหล่านั้นควรเป็นข้อกังวลแบบมุมฉาก (แต่สิ่งเหล่านี้ไม่เกี่ยวข้องกับความสวยงามในแง่มุมสำหรับกรณีพิเศษของ ContentType = application / x-www-form-urlencoded ดูหมายเหตุ 2 ด้านล่าง)

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

หมายเหตุ 2: หากเว็บเบราว์เซอร์เป็นวิธีหลักที่ผู้คนเข้าถึงเว็บแอปพลิเคชันของคุณและแอปพลิเคชัน / x-www-form-urlencodedเป็นประเภทเนื้อหาที่โพสต์คุณควรปฏิบัติตามกฎสำหรับประเภทเนื้อหานั้น และกฎสำหรับ application / x-www-form-urlencoded นั้นมีความเฉพาะเจาะจงมากขึ้น (และตรงไปตรงมา, ผิดปกติ): ในกรณีนี้คุณต้องตีความ URI ว่าเป็นชุดของพารามิเตอร์และไม่ใช่ตำแหน่งของทรัพยากร [นี่คือจุดเดียวของการใช้ประโยชน์ Powerlord ยก; อาจเป็นเรื่องยากที่จะใช้เว็บฟอร์มเพื่อโพสต์เนื้อหาไปยังเซิร์ฟเวอร์ของคุณ เพิ่งอธิบายแตกต่างกันเล็กน้อย]

หมายเหตุ 3: สตริงการสืบค้นเดิมมีไว้เพื่ออะไร RFC 3986 กำหนดสตริงเคียวรี HTTP เป็นส่วน URI ที่ทำงานเป็นวิธีที่ไม่เป็นลำดับชั้นในการค้นหาทรัพยากร

ในกรณีที่ผู้อ่านที่ถามคำถามนี้ต้องการถามสถาปัตยกรรม RESTful ที่ดี: รูปแบบสถาปัตยกรรม RESTful นั้นไม่จำเป็นต้องใช้รูปแบบ URI ในการทำงานในแบบที่เฉพาะเจาะจง RESTful Architecture เกี่ยวข้องกับคุณสมบัติอื่น ๆ ของระบบเช่นความสามารถในการแคชของทรัพยากรการออกแบบทรัพยากร (พฤติกรรมความสามารถและการเป็นตัวแทน) และความพึงพอใจของ idempotence หรือกล่าวอีกนัยหนึ่งการออกแบบให้เข้ากันได้กับโปรโตคอล HTTP และชุดคำกริยาวิธี HTTP :-) (ในคำอื่น ๆ สถาปัตยกรรมสงบไม่ presciptive มากกับวิธีการที่ทรัพยากรที่มีอยู่ .)

หมายเหตุสุดท้าย: บางครั้งพารามิเตอร์การสืบค้นจะถูกใช้เพื่อสิ่งอื่น ๆ ซึ่งไม่ใช่แหล่งข้อมูลหรือการเข้ารหัสเนื้อหา เคยเห็นพารามิเตอร์การสืบค้นเช่น 'PUT = true' หรือ 'POST = true' หรือไม่ สิ่งเหล่านี้เป็นวิธีแก้ปัญหาสำหรับเบราว์เซอร์ที่ไม่อนุญาตให้คุณใช้วิธี PUT และ POST ในขณะที่ค่าพารามิเตอร์ดังกล่าวถูกมองว่าเป็นส่วนหนึ่งของสตริงแบบสอบถาม URL (บนลวด) ผมยืนยันว่าพวกเขาไม่ได้เป็นส่วนหนึ่งของการค้นหาของ URL ในจิตวิญญาณ


66

คุณต้องการเหตุผลไหม นี่คือหนึ่ง:

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

ที่มา: มาตรฐาน HTML 4.01, มาตรา17.13 การส่งแบบฟอร์ม


10
นั่นเป็นเหตุผลที่ดี แต่ฉันคิดว่าการใช้งาน Javascript ของเบราว์เซอร์รุ่นใหม่ทำให้เป็นจุดที่สงสัย ฉันจะคิดเกี่ยวกับมัน - มันน่าสนใจในวิธีการพิสูจน์อักษรในอนาคต เพียงเพราะฉันไม่ได้ใช้แบบฟอร์มตอนนี้ไม่ได้หมายความว่าฉันจะไม่ต้องการในภายหลัง
Steven Huwig

9
การผสม GET กับ POST เป็นเพียงความคิดที่แย่มาก ๆ - ทำลาย HTTP อย่างมากและไม่มีเหตุผลที่ดี
aehlke

6
ตัวอย่างนั้นไม่ปรากฏในหน้าที่คุณลิงก์
Gareth

40
ถูกต้อง แต่แอตทริบิวต์เมธอดกำหนดว่า "ชุดข้อมูลฟอร์ม" รวมอยู่ในคำขออย่างไร เมื่อmethodโพสต์มีการกล่าวถึงการเปลี่ยน URI actionในรูปแบบใด และแน่นอนว่า URI ใด ๆ สามารถมีส่วนสตริงข้อความค้นหาอยู่แล้ว
Gareth

16
@ Powerlord นี่มันผิดนะ ลองตั้งค่าแบบฟอร์มเพื่อ POST ด้วยการกระทำเช่น /Books?bookCode=1234. เว็บเซิร์ฟเวอร์จะได้รับ vars ฟอร์ม POST และสตริงแบบสอบถาม
Jez

9

จากมุมมองการเขียนโปรแกรมสำหรับลูกค้ามันบรรจุพารามิเตอร์และผนวกเข้ากับ URL และดำเนินการ POST กับ GET ทางฝั่งเซิร์ฟเวอร์จะทำการประเมินพารามิเตอร์ขาเข้าจากการสอบถามแทนการลงรายการบัญชีไบต์ โดยทั่วไปมันล้าง

ในกรณีที่อาจมีข้อดี / ข้อเสียอาจเป็นได้ว่าแพลตฟอร์มไคลเอนต์เฉพาะทำงานกับรูทีน POST และ GET ในเครือข่ายสแต็กของพวกเขาเช่นเดียวกับวิธีที่เว็บเซิร์ฟเวอร์จัดการกับคำขอเหล่านั้น วิธีหนึ่งอาจมีประสิทธิภาพมากกว่าวิธีอื่น รู้ว่าจะเป็นแนวทางในการตัดสินใจของคุณที่นี่

อย่างไรก็ตามจากมุมมองของโปรแกรมเมอร์ฉันชอบอนุญาตให้ POST กับพารามิเตอร์ทั้งหมดในร่างกายหรือ GET ที่มี params ทั้งหมดใน url และละเว้นพารามิเตอร์ url ด้วยการร้องขอ POST ใด ๆ มันหลีกเลี่ยงความสับสน


8

ฉันคิดว่ามันยังคงสงบมากทีเดียวที่จะมีอาร์กิวเมนต์การสืบค้นที่ระบุทรัพยากรใน URL ในขณะที่รักษา payload เนื้อหาที่ จำกัด ไว้ในเนื้อหาของ POST สิ่งนี้จะแยกข้อควรพิจารณาของ "ฉันกำลังส่งอะไร" กับ "ฉันจะส่งใครไป"


5
คำถามไม่ได้เกี่ยวกับ REST
Steven Huwig

3
@ user359996 ไม่ใช่ API ของ HTTP ทั้งหมดที่เป็นที่สงบ ในความเป็นจริง API ส่วนใหญ่ที่อ้างว่าไม่ใช่ ที่จริงแล้วความสนุก REST ไม่ใช่ HTTP-only เท่านั้น
Alec Mev

4

RESTค่ายมีหลักการบางอย่างที่เราสามารถใช้ในการสร้างมาตรฐานวิธีที่เราใช้ HTTP คำกริยา สิ่งนี้มีประโยชน์เมื่อสร้าง RESTful API ตามที่คุณทำ

โดยสรุป: GET ควรเป็นแบบอ่านอย่างเดียวนั่นคือไม่มีผลต่อสถานะเซิร์ฟเวอร์ POST ใช้เพื่อสร้างทรัพยากรบนเซิร์ฟเวอร์ PUT ใช้เพื่ออัปเดตหรือสร้างทรัพยากร DELETE ใช้เพื่อลบทรัพยากร

กล่าวอีกนัยหนึ่งถ้าการกระทำ API ของคุณเปลี่ยนสถานะเซิร์ฟเวอร์ REST แนะนำให้เราใช้ POST / PUT / DELETE แต่ไม่ใช่ GET

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

เปรียบเทียบกับ GET ที่คุณสามารถทำได้บ่อยครั้งตามที่คุณต้องการ (idempotent)


13
REST camp บอกว่าคุณควรใช้ HTTP ตามที่กำหนดไว้ในข้อมูลจำเพาะ HTTP ie RFC2616 ไม่มีอะไรเพิ่มเติมไม่มีอะไรน้อย
Darrel Miller

1
@Darrel Refering ibm.com/developerworks/webservices/library/ws-restful : REST ขอให้ผู้พัฒนาใช้วิธีการ HTTP อย่างชัดเจนและสอดคล้องกับข้อกำหนดของโปรโตคอล หลักการออกแบบ REST พื้นฐานนี้สร้างการแม็พแบบหนึ่งต่อหนึ่งระหว่างการดำเนินการสร้างอ่านอัปเดตและลบ (CRUD) และวิธี HTTP ตามการแม็พนี้: ในการสร้างทรัพยากรบนเซิร์ฟเวอร์ให้ใช้ POST เพื่อดึงทรัพยากรใช้ GET หากต้องการเปลี่ยนสถานะของทรัพยากรหรืออัปเดตให้ใช้ PUT ในการลบหรือลบทรัพยากรให้ใช้ DELETE
แล่นเรือ

5
ขออภัย แต่มันผิดธรรมดา REST ต้องการการปฏิบัติตามอินเตอร์เฟสแบบสม่ำเสมอ หากคุณกำลังใช้ HTTP ดังนั้นอินเตอร์เฟซที่เหมือนกันนั้นถูกกำหนดไว้บางส่วนโดย RFC 2616 ในข้อมูลจำเพาะนั้นไม่มีการแมปแบบหนึ่งต่อหนึ่งระหว่างการสร้างอ่านอัปเดตและลบและวิธีการ HTTP
Darrel Miller

3
รับและลบแผนที่ค่อนข้างดีในการอ่านและลบใน CRUD แต่การใช้ PUT / POST สำหรับการอัปเดตและสร้างนั้นไม่ได้ตรงไปตรงมา ดูstackoverflow.com/questions/630453/put-vs-post-in-rest
dcstraw

5
เมื่อมองย้อนกลับไปใน 6 ปีต่อมาและเมื่อมองคำถามนี้แล้ว ~ 100k ครั้งฉันรู้สึกว่ามันคุ้มค่าที่จะอัพเดท Darrel ถูกต้องตามคำจำกัดความของ Fielding ของ REST ( ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm ) - ไม่มีการเอ่ยถึงการแม็พ HTTP กริยากับ CRUD คำแนะนำสำหรับนักพัฒนาของ IBM (ลิงก์ในความคิดเห็นด้านบน) สะท้อนถึงการปฏิบัติทั่วไปในการนำ RESTful API ไปใช้ไม่ใช่นิยามของ REST ของ Fielding
แล่นเรือ

-13

ฉันเห็นด้วย - อาจปลอดภัยกว่าหากใช้คำขอ GET หากคุณเพิ่งส่งข้อมูลใน URL ไม่ใช่ในเนื้อหา ดูคำถามที่คล้ายกันนี้สำหรับมุมมองเพิ่มเติมบางประการเกี่ยวกับแนวคิด POST + GET ทั้งหมด


17
หากการดำเนินการมีผลข้างเคียงแน่นอนว่าไม่ใช่ 'ปลอดภัย' ที่จะใช้วิธีการ GET เนื่องจากเบราว์เซอร์ถือว่า GET ทั้งหมดเป็น idempotent
dcstraw

เสิร์ชเอ็นจิ้นยังแปลงสิ่งนั้นในฝันร้ายเพราะ Google จะ "คลิก" ลิงก์ทั้งหมดที่มีคำขอ GET อย่างปลอดภัย แต่จะละเว้นทุกอย่างอื่น การออกจากบริการไม่ปลอดภัยนักที่โปรแกรมรวบรวมข้อมูลบริสุทธิ์สามารถลบฐานข้อมูลโดยไม่ตั้งใจได้
Alejandro
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.