วางกับ POST ใน REST


5372

ตาม HTTP / 1.1 Spec:

POSTวิธีการที่ใช้ในการขอให้เซิร์ฟเวอร์ต้นทางยอมรับกิจการที่แนบมาในคำขอเป็นผู้ใต้บังคับบัญชาใหม่ของทรัพยากรที่ระบุโดยRequest-URIในRequest-Line

ในคำอื่น ๆPOSTที่ใช้ในการสร้าง

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

นั่นคือPUTจะใช้ในการสร้างหรือเปลี่ยน

ดังนั้นควรใช้อันไหนในการสร้างทรัพยากร หรือต้องการสนับสนุนทั้งสองอย่าง?


56
การใช้คำจำกัดความใน HTTPbis - Roy อาจช่วยได้อย่างชัดเจน ดู: tools.ietf.org/html/ …
ทำเครื่องหมายนอตติงแฮม

16
เพียงนำความคิดเห็นของ @ MarkNottingham มาสู่การแก้ไขล่าสุดนี่คือPOSTและPUTตามที่กำหนดไว้บน HTTPbis
Marius Butuc

37
สำหรับฉันแล้วการอภิปรายนี้เกิดขึ้นจากการปฏิบัติทั่วไปของการใช้ REST ที่เกินขนาดโดยการอธิบายวิธีการ HTTP ในแง่ของการปฏิบัติการ CRUD
Stuporman

5
น่าเสียดายที่คำตอบแรกนั้นผิดเกี่ยวกับ POST ตรวจสอบคำตอบของฉันสำหรับคำอธิบายที่ดีขึ้นเกี่ยวกับความแตกต่าง: stackoverflow.com/a/18243587/2458234
7hi4g0

23
PUT และ POST เป็นทั้งวิธีที่ไม่ปลอดภัย อย่างไรก็ตาม PUT เป็น idempotent ในขณะที่ POST ไม่ใช่ - ดูเพิ่มเติมได้ที่: restcookbook.com/HTTP%20Methods/put-vs-post/…
Dinesh Saini

คำตอบ:


4239

โดยรวม:

ทั้ง PUT และ POST สามารถใช้ในการสร้างได้

คุณต้องถามว่า "คุณกำลังทำอะไรอยู่" เพื่อแยกแยะสิ่งที่คุณควรใช้ สมมติว่าคุณออกแบบ API สำหรับถามคำถาม หากคุณต้องการใช้ POST คุณจะต้องทำรายการคำถาม หากคุณต้องการใช้ PUT คุณก็จะทำเช่นนั้นกับคำถามเฉพาะ

สามารถใช้ได้ทั้งสองอย่างยอดเยี่ยมดังนั้นฉันควรใช้อันใดในการออกแบบ RESTful:

คุณไม่จำเป็นต้องรองรับทั้ง PUT และ POST

สิ่งที่ใช้แล้วถูกทิ้งไว้กับคุณ แต่เพียงจำไว้ว่าให้ใช้สิ่งที่ถูกต้องทั้งนี้ขึ้นอยู่กับวัตถุที่คุณอ้างอิงในคำขอ

ข้อควรพิจารณาบางประการ:

  • คุณตั้งชื่อวัตถุ URL ของคุณที่คุณสร้างไว้อย่างชัดเจนหรือปล่อยให้เซิร์ฟเวอร์ตัดสินใจ หากคุณตั้งชื่อพวกเขาให้ใช้ PUT หากคุณให้เซิร์ฟเวอร์ตัดสินใจใช้ POST
  • PUT เป็น idempotent ดังนั้นหากคุณใส่วัตถุสองครั้งจะไม่มีผลใด ๆ นี่เป็นคุณสมบัติที่ดีดังนั้นฉันจะใช้ PUT เมื่อเป็นไปได้
  • คุณสามารถอัปเดตหรือสร้างทรัพยากรด้วย PUT ด้วย URL วัตถุเดียวกัน
  • ด้วย POST คุณสามารถมี 2 คำขอที่มาพร้อมกันในการแก้ไข URL และพวกเขาอาจปรับปรุงส่วนต่าง ๆ ของวัตถุ

ตัวอย่าง:

ฉันเขียนต่อไปนี้เป็นส่วนหนึ่งของคำตอบอื่นใน SO เกี่ยวกับเรื่องนี้ :

โพสต์:

ใช้เพื่อแก้ไขและอัปเดตทรัพยากร

POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

โปรดทราบว่าต่อไปนี้เป็นข้อผิดพลาด:

POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

หากยังไม่ได้สร้าง URL คุณไม่ควรใช้ POST เพื่อสร้างขณะระบุชื่อ สิ่งนี้จะส่งผลให้เกิดข้อผิดพลาด 'ทรัพยากรไม่พบ' เพราะ<new_question>ยังไม่มี คุณควรวาง<new_question> ทรัพยากรบนเซิร์ฟเวอร์ก่อน

คุณสามารถทำสิ่งนี้เพื่อสร้างทรัพยากรโดยใช้ POST:

POST /questions HTTP/1.1
Host: www.example.com/

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

PUT:

ใช้เพื่อสร้างทรัพยากรหรือเขียนทับมัน ในขณะที่คุณระบุ URL ใหม่ของทรัพยากร

สำหรับทรัพยากรใหม่:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

ในการเขียนทับทรัพยากรที่มีอยู่:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

ยิ่งไปกว่านั้นRFC 7231 ตอนที่ 4.3.4 PUTระบุด้วย

4.3.4 PUT

วิธี PUT ร้องขอให้สถานะของทรัพยากรเป้าหมายเป็น createdหรือreplacedด้วยสถานะที่กำหนดโดยการแสดงที่ล้อมรอบในเพย์โหลดข้อความคำขอ


1026
ฉันคิดว่าไม่มีใครเครียดได้มากพอที่ความจริงที่ว่า PUT นั้นเป็น idempotent: หากเครือข่ายไม่เรียบร้อยและลูกค้าไม่แน่ใจว่าคำขอของเขาทำผ่านหรือไม่มันสามารถส่งครั้งที่สอง (หรือ 100) และรับประกันโดย HTTP spec ว่าสิ่งนี้มีผลเหมือนกับการส่งครั้งเดียว
Jörg W Mittag

77
@ Jörg W Mittag: ไม่จำเป็น ครั้งที่สองอาจส่งคืน 409 ความขัดแย้งหรือบางสิ่งบางอย่างหากคำขอได้รับการแก้ไขในระหว่างนี้
Mitar

632
ถ้าฉันไม่เข้าใจผิดสิ่งที่เราควรจะเน้นคือ PUT ถูกกำหนดให้เป็น idempotent คุณยังต้องเขียนเซิร์ฟเวอร์ของคุณในลักษณะที่ PUT ทำงานอย่างถูกต้องใช่ไหม อาจจะเป็นการดีกว่าถ้าพูดว่า "PUT ทำให้การขนส่งใช้ idempotence ซึ่งอาจส่งผลต่อพฤติกรรมของการขนส่งเช่นการแคช"
Ian Ni-Lewis

150
@ JörgWMittag Idempotence บทกลอน? วิธีการเกี่ยวกับ "ส่งและส่งและส่งเพื่อนของฉันมันไม่มีความแตกต่างในท้ายที่สุด"
James Beninger

39
คิดว่าพวกเขาเป็น: PUT = แทรกหรืออัปเดต; POST = ใส่ ดังนั้นเมื่อคุณทำสอง PUT - คุณได้รับหนึ่งระเบียนใหม่เมื่อคุณทำสองโพสต์ - คุณได้รับสองระเบียนใหม่
Eugen Konkov

2218

คุณสามารถค้นหาคำยืนยันบนเว็บที่พูดได้

ไม่ถูกต้องนัก


ดีกว่าคือเลือกระหว่าง PUT และ POST ตามidempotenceของการกระทำ

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

POSTอัปเดตทรัพยากรเพิ่มทรัพยากรในเครือหรือทำให้เกิดการเปลี่ยนแปลง POST ไม่ใช่ idempotent ในวิธีที่x++ไม่ใช้ idempotent


จากอาร์กิวเมนต์นี้ PUT ใช้สำหรับสร้างเมื่อคุณทราบ URL ของสิ่งที่คุณจะสร้าง สามารถใช้ POST เพื่อสร้างเมื่อคุณทราบ URL ของ "โรงงาน" หรือผู้จัดการสำหรับหมวดหมู่ของสิ่งที่คุณต้องการสร้าง

ดังนั้น:

POST /expense-report

หรือ:

PUT  /expense-report/10929

72
ฉันเห็นด้วยไม่ว่า idempotence จะเกี่ยวข้องกับเรื่องใดมันควรที่จะจัดการกับความกังวลอื่น ๆ เพราะการทำผิดนั้นอาจทำให้เกิดข้อผิดพลาดที่ไม่คาดคิดมากมาย
Josh

16
หาก POST สามารถอัปเดตทรัพยากรได้อย่างไรนั่นคือ idempotent อย่างไร ถ้าฉันเปลี่ยนนักเรียนอายุโดยใช้ PUT และทำ 10 เท่าคูณอายุนักเรียนจะเท่าเดิมถ้าฉันทำครั้งเดียว
Jack Ukleja

28
@ Schneider ในกรณีนี้เซิร์ฟเวอร์ของคุณกำลังพยายามอย่างมากที่จะรับประกัน idempotence แต่มันไม่ได้โฆษณา เบราว์เซอร์จะยังคงเตือนผู้ใช้หากพวกเขาพยายามโหลดคำขอ POST ซ้ำ
Tobu

47
@Schneider POST อาจสร้างทรัพยากรในเครือ ดังนั้นคุณสามารถ POST เพื่อรวบรวมเช่นPOST / รายงานค่าใช้จ่ายและมันจะสร้างเอนทิตีจำนวนมาก (รายงานค่าใช้จ่าย) บนเซิร์ฟเวอร์ของคุณตามปริมาณของคำขอที่คุณส่งแม้ว่าจะคล้ายกันหมด คิดว่าเป็นการแทรกแถวเดียวกันในตาราง DB (/ รายงานค่าใช้จ่าย) ด้วยคีย์หลักที่เพิ่มขึ้นอัตโนมัติ ข้อมูลยังคงเหมือนเดิมรหัส (URI ในกรณีนี้) สร้างขึ้นโดยเซิร์ฟเวอร์และแตกต่างกันสำหรับการแทรกอื่น ๆ (คำขอ) ดังนั้นเอฟเฟกต์ POST อาจเป็น idempotent แต่ก็อาจจะไม่ได้เช่นกัน ดังนั้น POST จึงไม่ใช่ idempotent
Snifff

11
สมมติว่าเรามีหน่วยงานที่อาจมีสองคุณสมบัติ - และname dateถ้าเรามีองค์กรที่มีที่มีอยู่nameและdateแต่แล้วทำการร้องขอไประบุเพียงnameพฤติกรรมที่เหมาะสมของPUTจะลบล้างdateของกิจการในขณะที่โพสต์อาจมีการปรับปรุงคุณสมบัติเฉพาะที่ระบุออกจากคุณสมบัติที่ไม่ระบุรายละเอียดตามที่พวกเขา ก่อนที่จะมีการร้องขอ เสียงนั้นถูกต้อง / สมเหตุสมผลหรือเป็นการใช้ที่ไม่เหมาะสมของPUT (ฉันเห็นการอ้างอิงถึงPATCHซึ่งดูเหมือนว่าจะเหมาะสมกว่า แต่ยังไม่มีอยู่)
Jon z

707
  • POSTไปยัง URL สร้างทรัพยากรลูกที่URL ที่เซิร์ฟเวอร์กำหนด
  • ใส่ลงใน URL สร้าง / แทนที่ทรัพยากรทั้งหมดที่URL ที่ลูกค้ากำหนด
  • PATCHไปยัง URL อัปเดตส่วนหนึ่งของทรัพยากรที่ URL ที่ลูกค้ากำหนดไว้

ข้อกำหนดที่เกี่ยวข้องสำหรับ PUT และ POST คือRFC 2616 §9.5ff

POST สร้างทรัพยากรย่อยดังนั้น POST จะ/itemsสร้างทรัพยากรที่อยู่ภายใต้/itemsทรัพยากร เช่น. /items/1. การส่งแพ็กเก็ตโพสต์เดียวกันสองครั้งจะสร้างทรัพยากรสองรายการ

PUTเป็นสำหรับการสร้างหรือเปลี่ยนทรัพยากรที่URL ที่เป็นที่รู้จักกันโดยลูกค้า

ดังนั้น: PUTเป็นเพียงตัวเลือกสำหรับ CREATE ที่ไคลเอ็นต์รู้จัก URL ก่อนที่จะสร้างทรัพยากร เช่น. /blogs/nigel/entry/when_to_use_post_vs_putเป็นชื่อที่ใช้เป็นรหัสทรัพยากร

PUTจะแทนที่ทรัพยากรที่ url ที่รู้จักหากมีอยู่แล้วดังนั้นการส่งคำขอเดียวกันสองครั้งจะไม่มีผลกระทบ ในคำอื่น ๆโทรไป PUT เป็น idempotent

RFC อ่านดังนี้:

ความแตกต่างพื้นฐานระหว่างคำขอ POST และ PUT สะท้อนให้เห็นในความหมายที่แตกต่างกันของ Request-URI URI ในคำขอ POST ระบุทรัพยากรที่จะจัดการกับเอนทิตีที่ปิดล้อม ทรัพยากรนั้นอาจเป็นกระบวนการยอมรับข้อมูลเกตเวย์ไปยังโปรโตคอลอื่นหรือเอนทิตีแยกต่างหากที่ยอมรับคำอธิบายประกอบ ในทางตรงกันข้าม URI ในคำขอ PUT จะระบุเอนทิตีที่แนบมากับคำขอ - ตัวแทนผู้ใช้รู้ว่า URI มีวัตถุประสงค์อะไรและเซิร์ฟเวอร์จะต้องไม่พยายามใช้คำขอกับทรัพยากรอื่น ๆ หากเซิร์ฟเวอร์ต้องการให้คำขอนั้นถูกนำไปใช้กับ URI อื่น

หมายเหตุ: PUT ส่วนใหญ่จะใช้เพื่ออัปเดตทรัพยากร (โดยแทนที่ในช่วงเวลาทั้งหมด) แต่เมื่อเร็ว ๆ นี้มีการเคลื่อนไหวไปสู่การใช้ PATCH เพื่ออัปเดตทรัพยากรที่มีอยู่ตามที่ PUT ระบุว่าจะแทนที่ทรัพยากรทั้งหมด RFC 5789

อัปเดต 2018 : มีกรณีที่สามารถทำเพื่อหลีกเลี่ยงการวาง ดู"ส่วนที่เหลือโดยไม่ใส่"

ด้วยเทคนิค "REST ปราศจาก PUT" ความคิดคือผู้บริโภคถูกบังคับให้โพสต์ทรัพยากรคำขอใหม่ 'ที่เป็นรูปธรรม' ดังที่กล่าวไว้ก่อนหน้านี้การเปลี่ยนที่อยู่ทางไปรษณีย์ของลูกค้าเป็น POST เป็นทรัพยากร“ ChangeOfAddress” ใหม่ไม่ใช่ PUT ของทรัพยากร“ ลูกค้า” ที่มีค่าฟิลด์ที่อยู่ทางไปรษณีย์ที่แตกต่างกัน

นำมาจากREST API Design - ตัวแบบทรัพยากรโดย Prakash Subramaniam of Thoughtworks

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


53
หรือจากด้านอื่น ๆ ของรั้ว: ใส่ถ้าลูกค้ากำหนดที่อยู่ของทรัพยากรที่เกิดขึ้นโพสต์ถ้าเซิร์ฟเวอร์ทำมัน
DanMan

3
ฉันคิดว่าคำตอบนี้ควรได้รับการแก้ไขเพื่อให้ชัดเจนยิ่งขึ้นในสิ่งที่ @DanMan ชี้ไปในวิธีที่ง่ายมาก สิ่งที่ฉันพบว่ามีค่ามากที่สุดในที่นี้คือโน้ตในตอนท้ายโดยระบุว่า PUT ควรใช้เพื่อแทนที่ทรัพยากรทั้งหมดเท่านั้น
Hermes

3
PATCH ไม่ใช่ตัวเลือกที่เหมือนจริงอย่างน้อยสองสามปี แต่ฉันเห็นด้วยกับอุดมการณ์
บดขยี้

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

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

221

สรุป:

สร้าง:

สามารถทำได้ทั้ง PUT หรือ POST ด้วยวิธีต่อไปนี้:

PUT

สร้างทรัพยากรใหม่ที่มีnewResourceIdเป็นตัวระบุภายใต้ทรัพยากร / URI ที่หรือคอลเลกชัน

PUT /resources/<newResourceId> HTTP/1.1 

โพสต์

สร้างทรัพยากรใหม่ภายใต้ทรัพยากร / URI ที่หรือคอลเลกชัน โดยปกติแล้วตัวระบุจะถูกส่งคืนโดยเซิร์ฟเวอร์

POST /resources HTTP/1.1

ปรับปรุง:

สามารถเพียง แต่จะดำเนินการกับการใส่ในวิธีต่อไปนี้:

PUT

การปรับปรุงทรัพยากรที่มีexistingResourceIdเป็นตัวระบุภายใต้ทรัพยากร / URI หรือคอลเลกชัน

PUT /resources/<existingResourceId> HTTP/1.1

คำอธิบาย:

เมื่อจัดการกับส่วนที่เหลือและ URI ทั่วไปคุณมีทั่วไปบนซ้ายและเฉพาะเจาะจงบนขวา ข้อมูลทั่วไปมักจะเรียกว่าคอลเลกชันและอื่น ๆเฉพาะรายการที่สามารถเรียกทรัพยากร โปรดทราบว่าทรัพยากรที่สามารถมีคอลเลกชัน

ตัวอย่าง:

<- ทั่วไป - เฉพาะ ->

URI: website.com/users/john
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource

URI:website.com/users/john/posts/23
website.com  - whole site
users        - collection of users
john         - item of the collection, or a resource
posts        - collection of posts from john
23           - post from john with identifier 23, also a resource

เมื่อคุณใช้ POST คุณมักจะอ้างอิงกับคอลเลกชันดังนั้นเมื่อใดก็ตามที่คุณพูดว่า:

POST /users HTTP/1.1

คุณกำลังโพสต์ของผู้ใช้ใหม่ให้กับผู้ใช้งาน คอลเลกชัน

หากคุณลองทำสิ่งต่อไปนี้:

POST /users/john HTTP/1.1

มันจะทำงาน แต่ความหมายที่คุณพูดว่าคุณต้องการที่จะเพิ่มทรัพยากรให้กับจอห์น คอลเลกชันภายใต้ผู้ใช้ คอลเลกชัน

เมื่อคุณกำลังใช้ PUT คุณกำลังหมายกับทรัพยากรเดียวหรือรายการที่อาจจะอยู่ในคอลเลกชัน ดังนั้นเมื่อคุณพูดว่า:

PUT /users/john HTTP/1.1

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

ข้อมูลจำเพาะ:

ผมขอเน้นบางส่วนที่สำคัญของข้อมูลจำเพาะ:

โพสต์

POSTวิธีการที่ใช้ในการขอให้เซิร์ฟเวอร์ต้นทางยอมรับกิจการที่แนบมาในคำขอเป็นใหม่ผู้ใต้บังคับบัญชาของทรัพยากรที่ระบุโดยขอ URI ในคำขอ-Line

ดังนั้นจะสร้างใหม่ทรัพยากรในคอลเลกชัน

PUT

PUTคำขอวิธีการที่นิติบุคคลที่แนบมาจะถูกเก็บไว้ภายใต้การจัดขอ URI หาก Request-URI อ้างถึงทรัพยากรที่มีอยู่แล้วนิติบุคคลที่ปิดอยู่ควรได้รับการพิจารณาว่าเป็นรุ่นที่แก้ไขขององค์กรที่อยู่ในเซิร์ฟเวอร์ต้นทาง หาก Request-URI ไม่ได้ชี้ไปที่ทรัพยากรที่มีอยู่และ URI นั้นสามารถกำหนดเป็นทรัพยากรใหม่ได้โดยตัวแทนผู้ใช้ที่ร้องขอเซิร์ฟเวอร์ต้นทางสามารถสร้างทรัพยากรด้วย URI นั้น "

ดังนั้นการสร้างหรือปรับปรุงอยู่บนพื้นฐานของการดำรงอยู่ของทรัพยากร

อ้างอิง:


11
โพสต์นี้มีประโยชน์สำหรับฉันในการทำความเข้าใจว่า POST เพิ่ม "บางสิ่งบางอย่าง" เป็นเด็กในคอลเล็กชันที่กำหนด (URI) ในขณะที่ PUT กำหนด "บางอย่าง" ไว้ที่ตำแหน่ง URI ที่กำหนดไว้อย่างชัดเจน
kwah

3
นี่เป็นคำตอบที่ดีที่สุดที่นี่ฉันคิดว่า: "POST ไม่สามารถอัปเดตทรัพยากร" ไร้สาระได้ ฉันชอบข้อความของคุณ "การอัปเดตสามารถทำได้ด้วย PUT เท่านั้น"
โทมัส

4
ไม่ PUT ไม่ใช่สำหรับการอัปเดตหรือสร้าง มันมีไว้สำหรับแทนที่ โปรดทราบว่าคุณไม่สามารถแทนที่สิ่งใดเพื่อผลของการสร้าง
thecoshman

2
@ 7hi4g0 PUT สำหรับการอัปเดตด้วยการแทนที่แบบสมบูรณ์หรืออีกนัยหนึ่งคือแทนที่ คุณแทนที่สิ่งใดสิ่งหนึ่งหรือบางสิ่งบางอย่างด้วยสิ่งใหม่ที่สมบูรณ์ PUT ไม่ได้ทำการเปลี่ยนแปลงเล็กน้อย (เว้นแต่คุณจะมีไคลเอ็นต์ที่ทำการเปลี่ยนแปลงเล็กน้อยและนำเสนอเวอร์ชันใหม่ทั้งหมดแม้สิ่งที่เหลืออยู่จะเหมือนกัน) สำหรับการดัดแปลงบางส่วน PATCH เป็นวิธีการที่เลือก
thecoshman

1
@thecoshman คุณทำได้ แต่ไม่ชัดเจนเกินไปที่การสร้างจะครอบคลุมอยู่ในนั้นด้วย ในกรณีนี้มันจะดีกว่าที่จะชัดเจน
7hi4g0

175

POST หมายถึง "สร้างใหม่" ใน "นี่คืออินพุตสำหรับการสร้างผู้ใช้สร้างให้ฉัน"

PUT หมายถึง "แทรกแทนที่หากมีอยู่แล้ว" เช่นเดียวกับใน "นี่คือข้อมูลสำหรับผู้ใช้ 5"

คุณPOSTไปที่ example.com/users เนื่องจากคุณยังไม่รู้จักURLผู้ใช้คุณต้องการให้เซิร์ฟเวอร์สร้างมันขึ้นมา

คุณPUTto example.com/users/id เนื่องจากคุณต้องการแทนที่ / สร้างผู้ใช้เฉพาะ

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

คำแนะนำทั่วไปคือใช้POSTเมื่อคุณต้องการให้เซิร์ฟเวอร์อยู่ในการควบคุมการURLสร้างทรัพยากรของคุณ ใช้เป็นPUTอย่างอื่น ชอบมากกว่า PUT POST


12
ความเลอะเทอะอาจทำให้เป็นเรื่องปกติที่จะสอนว่ามีเพียงสองคำกริยาที่คุณต้องการ: GET และ POST รับเพื่อรับ POST ที่จะเปลี่ยน แม้แต่ PUT และ DELETE ก็สามารถทำได้โดยใช้ POST การถามว่า PUT หมายถึงอะไรจริง ๆ 25 ปีต่อมาอาจเป็นสัญญาณที่เราได้เรียนรู้ว่ามันผิดในตอนแรก ความนิยมของ REST ผลักดันให้ผู้คนกลับไปสู่พื้นฐานที่ตอนนี้เราต้องแก้ปัญหาความผิดพลาดที่ผ่านมา โพสต์มากเกินไปและตอนนี้สอนผิดปกติ ส่วนที่ดีที่สุด: "การโพสต์สองครั้งด้วยข้อมูลเดียวกันหมายถึงสร้าง [แหล่งข้อมูล] เหมือนกันสองรายการ" จุดที่ดี!
maxpolk

1
คุณสามารถใช้ PUT เพื่อสร้างระเบียนด้วย ID ได้อย่างไรเช่นในตัวอย่างของคุณuser 5ถ้ายังไม่มี? คุณไม่หมายถึงupdate, replace if already existsเหรอ หรืออะไรก็ได้
ลูกา

@ Colton: ฉันหมายถึงสิ่งที่ฉันเขียน คุณแทรกผู้ใช้ 5 หากคุณยังไม่ได้ใส่ / ผู้ใช้ / 5 และ # 5
Alexander Torstling

@Coulton: และPUTยังสามารถใช้เพื่อแทนที่ค่าของทรัพยากรที่มีอยู่ในสิ่งทั้งปวง
DavidRR

1
"ชอบวางมากกว่าโพสต์" ... สนใจที่จะพิสูจน์หรือไม่
thecoshman

173

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

ดังนั้น: ในการบันทึกผู้ใช้ที่มีอยู่หรือหนึ่งในที่ที่ลูกค้าสร้างรหัสและมันได้รับการตรวจสอบว่า ID นั้นไม่ซ้ำกัน:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.com

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.com

มิฉะนั้นให้ใช้ POST เพื่อสร้างวัตถุในขั้นต้นและ PUT เพื่ออัปเดตวัตถุ:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.com

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.com

17
POST /usersอันที่จริงมันควรจะเป็น (โปรดทราบว่า/usersเป็นพหูพจน์) สิ่งนี้มีผลต่อการสร้างผู้ใช้ใหม่และทำให้เป็นแหล่งข้อมูลย่อยของ/usersคอลเลกชัน
DavidRR

6
@DavidRR ให้ความเป็นธรรมวิธีการจัดการกลุ่มเป็นอีกการอภิปรายทั้งหมด GET /usersเหมาะสมแล้วที่อ่านได้ตามที่คุณต้องการ แต่ฉันจะโอเคกับGET /user/<id>หรือPOST /user(ด้วยน้ำหนักบรรทุกสำหรับผู้ใช้ใหม่ที่กล่าว) เพราะมันอ่านอย่างถูกต้อง 'ให้ฉันผู้ใช้ 5' เป็นคี่ แต่ 'รับฉันผู้ใช้ 5' เป็นธรรมชาติมากขึ้น ผมอาจจะยังคงล้มลงบนด้านข้างของ pluralisation แม้ว่า :)
thecoshman

126

ใช้ POST เพื่อสร้างและ PUT เพื่ออัปเดต นั่นเป็นวิธีที่ Ruby on Rails ทำเช่นนั้น

PUT    /items/1      #=> update
POST   /items        #=> create

4
POST /itemsเพิ่มรายการใหม่ให้กับทรัพยากรที่กำหนดไว้แล้ว ('รายการ') มันไม่ได้ดังที่คำตอบบอกว่า "สร้างกลุ่ม" ฉันไม่เข้าใจว่าทำไมถึงมี 12 คะแนน
David J.

Rails ไม่สนับสนุน 'สร้างกลุ่ม' ผ่าน REST ในการ 'สร้างกลุ่ม' ซึ่งฉันหมายถึง 'สร้างทรัพยากร' คุณต้องทำผ่านซอร์สโค้ด
David J.

8
นี่เป็นแนวทางที่เป็นธรรม แต่เป็นการใช้อย่างแพร่หลาย เช่นเดียวกับคำตอบอื่น ๆ ที่กล่าวถึงสามารถใช้วิธีใดวิธีหนึ่งในการสร้างและอัปเดต
แบรดโคช์

2
ฉันเห็นด้วยกับคำตอบด้วยการปรับเปลี่ยนเล็กน้อย ใช้ POST เพื่อสร้างและ PUT เพื่ออัปเดตทรัพยากรอย่างสมบูรณ์ สำหรับการอัพเดทบางส่วนเราสามารถใช้ PUT หรือ PATCH ช่วยบอกว่าเราต้องการอัพเดทสถานะของกลุ่ม เราสามารถใช้ PUT / กลุ่ม / 1 / สถานะด้วยสถานะเป็นคำขอน้ำหนักบรรทุกหรือ PATCH / กลุ่ม / 1 พร้อมรายละเอียดเกี่ยวกับการดำเนินการในส่วนของข้อมูล
java_geek

2
ก็ควรที่จะทำให้เห็นได้ชัดว่าPUT /items/42ยังเป็นที่ถูกต้องสำหรับการสร้างทรัพยากรแต่ถ้าลูกค้ามีสิทธิพิเศษในการตั้งชื่อทรัพยากร (Rails อนุญาตให้ลูกค้าใช้สิทธิ์การตั้งชื่อนี้ได้หรือไม่)
DavidRR

123

ทั้งสองใช้สำหรับการส่งข้อมูลระหว่างไคลเอนต์ไปยังเซิร์ฟเวอร์ แต่มีความแตกต่างเล็กน้อยระหว่างพวกเขาซึ่ง ได้แก่ :

ป้อนคำอธิบายภาพที่นี่

การเปรียบเทียบ:

  • ใส่เช่นเอาและวางมันอยู่ที่ไหน
  • โพสต์เป็นส่งจดหมายในที่ทำการไปรษณีย์

ป้อนคำอธิบายรูปภาพที่นี่

สื่อโซเชียล / เครือข่ายแบบอะนาล็อก:

  • โพสต์บนโซเชียลมีเดีย: เมื่อเราโพสต์ข้อความมันจะสร้างโพสต์ใหม่
  • ใส่ (เช่นแก้ไข) สำหรับข้อความที่เราโพสต์แล้ว

21
@MobileMon ไม่วิธี REST ไม่ใช่ CRUD
jlr

1
ฉันจะบอก PUT สำหรับ UPSER
Hola Soy Edu Feliz Navidad

@MobileMon no: POST เมื่อคุณสร้างทรัพยากรใหม่และคุณไม่รู้จุดสุดท้ายที่จะได้รับ ใส่สำหรับกรณีอื่น ๆ
Portekoi

67

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

หากคุณมีข้อสงสัยเกี่ยวกับวิธีการใช้ REST ใน HTTP คุณสามารถดูข้อมูลจำเพาะAtom Publication Protocol (AtomPub)ได้ตลอดเวลา AtomPub เป็นมาตรฐานสำหรับการเขียนเว็บเซอร์ RESTful ด้วย HTTP ที่พัฒนาโดยผู้ทรงคุณวุฒิ HTTP และ REST จำนวนมากโดยมีข้อมูลบางส่วนจาก Roy Fielding ผู้ประดิษฐ์ของ REST และ (co-) นักประดิษฐ์ของ HTTP เอง

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

นี่คือสิ่งที่ AtomPub ได้พูดเกี่ยวกับการสร้างทรัพยากร (ส่วนที่ 9.2):

ในการเพิ่มสมาชิกในกลุ่มลูกค้าส่งคำขอ POST ไปยัง URI ของกลุ่ม


8
ไม่มีอะไรผิดปกติกับการอนุญาตให้ PUT สร้างทรัพยากร เพิ่งทราบว่ามันหมายความว่าลูกค้าให้ URL
Julian Reschke

5
มีบางอย่างผิดปกติในการอนุญาตให้ PUT สร้างทรัพยากร: ไคลเอนต์มี URL นั่นคืองานของเซิร์ฟเวอร์!
Joshcodes

@Joshcodes ไม่ใช่กรณีที่เป็นหน้าที่ของเซิร์ฟเวอร์ในการสร้างรหัสลูกค้า ฉันเห็นการออกแบบมากขึ้นที่ให้ลูกค้าสร้าง UUID บางประเภทเป็น id ทรัพยากร การออกแบบนี้ให้ยืมโดยเฉพาะอย่างยิ่งเพื่อเพิ่มขนาด
Justin Ohms

@JustinOhms ฉันเห็นด้วยกับจุดของคุณเกี่ยวกับลูกค้าที่สร้างรหัส (หมายเหตุด้าน: ระบบทั้งหมดที่ออกแบบโดยฉันตั้งแต่ประมาณปี 2008 ต้องการให้ลูกค้าสร้าง ID เป็น UUID / Guid) ไม่ได้หมายความว่าลูกค้าควรระบุ URL
Joshcodes

1
ใช่ถ้ามีทรัพยากรอยู่แล้วให้ใช้ PUT อย่างไรก็ตามในเกือบทุกกรณีควรสร้างทรัพยากรด้วย POST และไคลเอนต์ไม่ควรระบุ URL Roy Fielding เห็นด้วยกับคำชี้แจงนี้ FWIW: roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Joshcodes

61

การตัดสินใจว่าจะใช้ PUT หรือ POST เพื่อสร้างทรัพยากรบนเซิร์ฟเวอร์ที่มี HTTP + REST API ขึ้นอยู่กับว่าใครเป็นเจ้าของโครงสร้าง URL การที่ลูกค้ารู้หรือมีส่วนร่วมในการกำหนดโครงสร้าง URL คือการเชื่อมต่อที่ไม่จำเป็นคล้ายกับข้อต่อที่ไม่พึงประสงค์ที่เกิดขึ้นจาก SOA การหลบหลีกข้อต่อประเภทนี้คือเหตุผลที่ REST ได้รับความนิยมมาก ดังนั้นวิธีการใช้ที่เหมาะสมคือ POST มีข้อยกเว้นสำหรับกฎนี้และจะเกิดขึ้นเมื่อลูกค้าต้องการรักษาการควบคุมโครงสร้างตำแหน่งของทรัพยากรที่ปรับใช้ นี่เป็นของหายากและน่าจะหมายความว่ามีบางอย่างผิดปกติ

ณ จุดนี้บางคนจะโต้แย้งว่าหากใช้RESTful-URLลูกค้าจะทราบ URL ของทรัพยากรและดังนั้นจึงเป็นที่ยอมรับ PUT ท้ายที่สุดนี่คือเหตุผลว่าทำไม Ruby on Rails ซึ่งเป็นที่ยอมรับในระดับมาตรฐาน, URL ของ Django นั้นสำคัญดูที่ Twitter API … blah blah blah คนเหล่านั้นต้องเข้าใจว่าไม่มีสิ่งเช่น Restful-URLและRoy Fielding ระบุว่า :

REST API ต้องไม่กำหนดชื่อหรือลำดับชั้นของทรัพยากรคงที่ (การเชื่อมต่อที่ชัดเจนของไคลเอ็นต์และเซิร์ฟเวอร์) เซิร์ฟเวอร์ต้องมีอิสระในการควบคุมเนมสเปซของตนเอง อนุญาตให้เซิร์ฟเวอร์สอนลูกค้าเกี่ยวกับวิธีการสร้าง URIs ที่เหมาะสมเช่นทำในรูปแบบ HTML และเทมเพลต URI โดยการกำหนดคำแนะนำเหล่านั้นภายในประเภทสื่อและความสัมพันธ์ของลิงก์ [ความล้มเหลวที่นี่หมายถึงว่าลูกค้ากำลังสมมติโครงสร้างทรัพยากรเนื่องจากข้อมูลนอกแถบเช่นมาตรฐานโดเมนเฉพาะซึ่งเป็นข้อมูลเชิงเทียบเท่ากับหน้าที่การทำงานของ RPC]

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

แนวคิดของRESTful-URLเป็นการละเมิด REST เนื่องจากเซิร์ฟเวอร์รับผิดชอบโครงสร้าง URL และควรตัดสินใจว่าจะใช้อย่างไรเพื่อหลีกเลี่ยงการเชื่อมต่อ หากสิ่งนี้ทำให้คุณสับสนเกี่ยวกับความสำคัญของการค้นพบตัวเองในการออกแบบ API

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

  1. ลูกค้าโพสต์ทรัพยากรใหม่ไปยังเซิร์ฟเวอร์
  2. เซิร์ฟเวอร์ประมวลผลคำขอและส่งการตอบกลับ
  3. ลูกค้าไม่เคยได้รับการตอบสนอง
  4. เซิร์ฟเวอร์ไม่ทราบว่าลูกค้าไม่ได้รับการตอบสนอง
  5. ไคลเอ็นต์ไม่มี URL สำหรับทรัพยากร (ดังนั้น PUT จึงไม่ใช่ตัวเลือก) และทำซ้ำ POST
  6. POST ไม่ใช่ idempotent และเซิร์ฟเวอร์ ...

ขั้นตอนที่ 6 คือที่ที่คนทั่วไปสับสนเกี่ยวกับสิ่งที่ต้องทำ อย่างไรก็ตามไม่มีเหตุผลในการสร้าง kludge เพื่อแก้ไขปัญหานี้ สามารถใช้ HTTP แทนได้ตามที่ระบุในRFC 2616และเซิร์ฟเวอร์ตอบกลับ:

10.4.10 409 ความขัดแย้ง

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

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

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

การตอบกลับด้วยรหัสสถานะ 409 ความขัดแย้งเป็นการขอความช่วยเหลือที่ถูกต้องเพราะ :

  • การดำเนินการ POST ของข้อมูลที่มี ID ซึ่งตรงกับทรัพยากรที่มีอยู่แล้วในระบบคือ“ ความขัดแย้งกับสถานะปัจจุบันของทรัพยากร”
  • เนื่องจากส่วนสำคัญสำหรับลูกค้าที่จะเข้าใจเซิร์ฟเวอร์มีทรัพยากรและดำเนินการที่เหมาะสม นี่คือ“ สถานการณ์ที่คาดว่าผู้ใช้จะสามารถแก้ไขข้อขัดแย้งและส่งคำร้องขอใหม่ได้”
  • การตอบสนองที่มี URL ของทรัพยากรที่มี ID ที่ขัดแย้งกันและเงื่อนไขที่เหมาะสมสำหรับทรัพยากรจะให้ "ข้อมูลเพียงพอสำหรับผู้ใช้หรือตัวแทนผู้ใช้ในการแก้ไขปัญหา" ซึ่งเป็นกรณีที่เหมาะสำหรับ RFC 2616

อัปเดตตามการเปิดตัวของ RFC 7231 เพื่อแทนที่ 2616

RFC 7231ถูกออกแบบมาเพื่อแทนที่ 2616 และในส่วน 4.3.3อธิบายการตอบสนองที่เป็นไปได้สำหรับ POST

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

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

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้อ่านบทความ


การตอบสนองต่อความขัดแย้ง 409 จะเป็นรหัสที่เหมาะสมสำหรับบางอย่างเช่นพยายามสร้างบัญชีใหม่ด้วยชื่อผู้ใช้ที่มีอยู่แล้วหรือไม่? ฉันใช้ 409 สำหรับข้อขัดแย้งเกี่ยวกับเวอร์ชันโดยเฉพาะ แต่หลังจากอ่านคำตอบของคุณแล้วฉันสงสัยว่าไม่ควรใช้สำหรับคำขอ "ซ้ำ" ใด ๆ
Eric B.

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

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

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

การอธิบายสิ่งต่าง ๆ โดยใช้ภาษาที่สั้นและมีประสิทธิภาพเป็นทักษะที่พึงประสงค์เช่นกัน
Junchen Liu

53

ฉันชอบคำแนะนำนี้จากคำจำกัดความของ RFC 2616 ของ PUT :

ความแตกต่างพื้นฐานระหว่างคำขอ POST และ PUT สะท้อนให้เห็นในความหมายที่แตกต่างกันของ Request-URI URI ในคำขอ POST ระบุทรัพยากรที่จะจัดการกับเอนทิตีที่ปิดล้อม ทรัพยากรนั้นอาจเป็นกระบวนการยอมรับข้อมูลเกตเวย์ไปยังโปรโตคอลอื่นหรือเอนทิตีแยกต่างหากที่ยอมรับคำอธิบายประกอบ ในทางตรงกันข้าม URI ในคำขอ PUT จะระบุเอนทิตีที่แนบมากับคำขอ - ตัวแทนผู้ใช้รู้ว่า URI มีวัตถุประสงค์อะไรและเซิร์ฟเวอร์จะต้องไม่พยายามใช้คำขอกับทรัพยากรอื่น ๆ

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

ฉันตีความสิ่งนี้และข้อกำหนดของ idempotency บน PUT เพื่อหมายความว่า:

  • POST เหมาะสำหรับการสร้างวัตถุใหม่ภายใต้คอลเล็กชัน (และการสร้างไม่จำเป็นต้องเป็น idempotent)
  • PUT นั้นดีสำหรับการอัพเดตออบเจ็กต์ที่มีอยู่แล้ว
  • POST ยังสามารถใช้สำหรับการอัพเดทที่ไม่ใช่ idempotent สำหรับวัตถุที่มีอยู่ (โดยเฉพาะอย่างยิ่งการเปลี่ยนส่วนของวัตถุโดยไม่ระบุสิ่งทั้งหมด - ถ้าคุณคิดเกี่ยวกับมันการสร้างสมาชิกใหม่ของคอลเลกชันเป็นกรณีพิเศษของประเภทนี้ อัปเดตจากมุมมองของคอลเลกชัน)
  • PUT ยังสามารถใช้สำหรับการสร้างถ้าหากคุณอนุญาตให้ไคลเอ็นต์ตั้งชื่อทรัพยากร แต่เนื่องจากลูกค้า REST ไม่ควรคาดเดาเกี่ยวกับโครงสร้าง URL นี่จึงเป็นสิ่งที่ควรทำ

3
"POST สามารถใช้สำหรับการอัปเดตที่ไม่ใช่ idempotent สำหรับวัตถุที่มีอยู่ (โดยเฉพาะอย่างยิ่งการเปลี่ยนบางส่วนของวัตถุโดยไม่ระบุสิ่งทั้งหมด" นั่นคือสิ่งที่ PATCH ใช้สำหรับ
Snuggs

48

ในระยะสั้น:

PUTเป็น idempotent โดยที่สถานะของทรัพยากรจะเหมือนกันหากการดำเนินการเดียวกันถูกเรียกใช้งานครั้งเดียวหรือหลายครั้ง

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

คล้ายคลึงกับแบบสอบถามฐานข้อมูล

ใส่คุณคิดคล้ายกับ "UPDATE STUDENT SET address =" abc "โดยที่ id =" 123 ";

โพสต์คุณสามารถนึกถึงบางสิ่งเช่น "INSERT INTO STUDENT (ชื่อที่อยู่) ค่านิยม (" abc "," xyzzz ");

รหัสนักศึกษาถูกสร้างขึ้นโดยอัตโนมัติ

ด้วย PUT หากดำเนินการค้นหาเดียวกันหลายครั้งหรือครั้งเดียวสถานะตาราง STUDENT จะยังคงเหมือนเดิม

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

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

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


6
สำหรับPUTคล้ายกับINSERT หรือ UPDATEแบบสอบถาม
Eugen Konkov

1
จริง ๆ แล้วคุณสามารถคิดคล้ายกับ "UPDATE STUDENT SET address =" abc "โดยที่ id =" 123 "จะเป็นคำสั่งสำหรับ PATCH" UPDATE STUDENT SET address = "abc", ชื่อ = "newname" โดยที่ id = " 123 "จะเป็นการเปรียบเทียบที่ถูกต้องสำหรับ PUT
mko

สามารถใช้ Put สำหรับ INSERT ได้ ตัวอย่างเช่นหากเซิร์ฟเวอร์ของคุณตรวจพบว่าคุณพยายามอัปโหลดไฟล์เดียวกันหลายครั้งมันจะทำให้คำขอ idempotent ของคุณ (ไม่มีการอัปโหลดไฟล์ใหม่)
kiwicomb123

43

POST เปรียบเสมือนการโพสต์จดหมายไปยังกล่องจดหมายหรือโพสต์อีเมลไปยังคิวอีเมล PUT เป็นเหมือนเมื่อคุณวางวัตถุในหลุม cubby หรือสถานที่บนชั้นวาง (มีที่อยู่ที่รู้จัก)

ด้วย POST คุณกำลังโพสต์ไปยังที่อยู่ของ QUEUE หรือ COLLECTION ด้วย PUT คุณกำลังใส่ที่อยู่ของรายการ

PUT คือ idempotent คุณสามารถส่งคำขอ 100 ครั้งและมันจะไม่สำคัญ POST ไม่ใช่ idempotent หากคุณส่งคำขอ 100 ครั้งคุณจะได้รับ 100 อีเมลหรือ 100 ตัวอักษรในกล่องไปรษณีย์ของคุณ

กฎทั่วไป: หากคุณทราบ ID หรือชื่อของรายการให้ใช้ PUT หากคุณต้องการให้ ID หรือชื่อของรายการที่จะได้รับมอบหมายจากบุคคลที่ได้รับใช้ POST

โพสต์กับ PUT


1
ไม่ PUT บอกเป็นนัยว่าคุณรู้จัก URL หากคุณรู้ ID เท่านั้นให้โพสต์ด้วย ID นั้นเพื่อรับ URL
Joshcodes

6
ID เป็นส่วนหนึ่งของ URL ดังนั้นใช่ใช้ PUT หากคุณรู้จัก URL (ซึ่งรวมถึงรหัสด้วย)
Homer6

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

@Joshcodes นั่นคือสมมติว่า REST? ในสถาปัตยกรรม RESTful id ไอเท็มนั้นเป็นส่วนหนึ่งของ URL อย่างแน่นอนเช่นเดียวกับใน: / people / 123 ฉันชอบไซต์นี้สำหรับ REST: microformats.org/wiki/rest/urls
Beez

1
@Beez ลิงก์ mircoformats แนะนำวิธีที่ดีสำหรับเซิร์ฟเวอร์ในการจัดโครงสร้าง URL แต่เซิร์ฟเวอร์กำหนด URL ลูกค้าไม่เคยทำเช่นนี้มาก่อน ดูคำตอบหรือบทความที่เกี่ยวข้องของฉันหากคุณไม่เข้าใจ
Joshcodes

39

คำตอบใหม่ (ตอนนี้ฉันเข้าใจส่วนที่เหลือดีกว่า):

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

PUT x(หากxระบุทรัพยากร ): "แทนที่เนื้อหาของทรัพยากรที่ระบุxด้วยเนื้อหาของฉัน"

PUT x(หากxไม่ได้ระบุทรัพยากร): "สร้างทรัพยากรใหม่ที่มีเนื้อหาของฉันและใช้xเพื่อระบุ"

POST x: "เก็บเนื้อหาของฉันและให้ตัวระบุที่ฉันสามารถใช้เพื่อระบุทรัพยากร (เก่าหรือใหม่) ที่มีเนื้อหาดังกล่าว (อาจผสมกับเนื้อหาอื่น ๆ ) ทรัพยากรที่กล่าวมาควรจะเหมือนกันหรือน้อยกว่าที่xระบุ" " ทรัพยากรของyเป็นทรัพยากรรองของทรัพยากรx " โดยทั่วไปแล้ว แต่ไม่จำเป็นต้องดำเนินการโดยการทำให้yเป็น subpath ของx (เช่นx = /fooและy = /foo/bar) และปรับเปลี่ยนการแสดงทรัพยากรของxเพื่อสะท้อนการดำรงอยู่ ของทรัพยากรใหม่เช่นด้วยไฮเปอร์ลิงก์ไปยังyทรัพยากรและข้อมูลเมตาบางส่วน สิ่งหลังเท่านั้นที่มีความสำคัญต่อการออกแบบที่ดีเนื่องจาก URL มีความทึบใน REST - คุณควรจะใช้สื่อสิ่งพิมพ์แทนการสร้าง URL ฝั่งไคลเอ็นต์เพื่อสำรวจบริการ

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

คำตอบเดิม (อาจอ่านง่ายกว่า) :

PUT /something(หาก/somethingมีอยู่แล้ว): "เอาทุกอย่างที่คุณมี/somethingและแทนที่ด้วยสิ่งที่ฉันให้คุณ"

PUT /something(หาก/somethingยังไม่มีอยู่): "เอาสิ่งที่ฉันให้คุณมาใส่ไว้/something"

POST /something: "นำสิ่งที่ฉันให้คุณไปวางไว้ที่ใดก็ได้ตามที่คุณต้องการ/somethingตราบใดที่คุณให้ URL กับฉันเมื่อคุณทำเสร็จ"


แต่คุณจะใช้ PUT เพื่อสร้างทรัพยากรใหม่ได้อย่างไรหากไม่มีอยู่ในขณะที่วิธีการสร้าง ID ของคุณใช้การเพิ่มอัตโนมัติ? โดยปกติ ORM จะสร้าง ID ให้คุณโดยอัตโนมัติเช่นในแบบที่คุณต้องการให้เป็น POST มันหมายความว่าถ้าคุณต้องการที่จะนำ PUT ไปใช้อย่างถูกวิธีคุณต้องเปลี่ยนการสร้าง id อัตโนมัติของคุณหรือไม่? นี่มันอึดอัดถ้าคำตอบคือใช่
Roni Axelrad

1
@RoniAxelrad: PUT เปรียบเสมือนฐานข้อมูลคำสั่ง "INSERT หรือ UPDATE" ที่คุณรวมรหัสไว้ในคำสั่งเพื่อให้สามารถใช้ได้เฉพาะที่ที่คุณสามารถรับประกันว่าจะไม่มีการชนกัน เช่น. โดเมนของคุณมี 'คีย์ธรรมชาติ' หรือคุณใช้ guid POST เปรียบเสมือนการแทรกลงในตารางด้วยคีย์การเพิ่มอัตโนมัติ คุณจะต้องได้รับการบอกกล่าวจากฐานข้อมูลว่า ID นั้นได้รับหลังจากที่มันถูกแทรก โปรดทราบว่า "INSERT หรือ UPDATE" ของคุณจะแทนที่ข้อมูลก่อนหน้านี้หากมีอยู่
Nigel Thorne

@NigelThorne ขอบคุณสำหรับคำตอบของคุณ ดังนั้นถ้าเช่นฉันกำลังพยายามวางหนังสือ id 10 ด้วย URI: PUT books / 10 หากไม่มี id ของหนังสือ 10 ฉันควรสร้างหนังสือที่มี id 10 ใช่ไหม แต่ฉันไม่สามารถควบคุมตัวสร้าง ID ตัวสร้างได้เนื่องจากเป็นการเพิ่มอัตโนมัติ ฉันควรทำอย่างไรในสถานการณ์นั้น
Roni Axelrad

1
@RoniAxelrad REST PUT ไปยัง ID ที่ไม่มีอยู่คือคำขอไปยังเซิร์ฟเวอร์เพื่อสร้างทรัพยากร ยังขึ้นอยู่กับเซิร์ฟเวอร์เพื่อตัดสินใจว่าต้องการอนุญาตหรือไม่ เซิร์ฟเวอร์อยู่ในความดูแล มันสามารถตอบกลับด้วย "ไม่ฉันจะไม่ทำอย่างนั้น" คุณทำเช่นนั้นแล้วหากผู้ใช้มีสิทธิ์ไม่เพียงพอ ... ฯลฯ ไม่เป็นไรที่เซิร์ฟเวอร์จะพูดว่า "ไม่" REST เป็นแบบแผนที่ให้เรากำหนดความหมายของคำขอประเภทต่าง ๆ ... เซิร์ฟเวอร์ของคุณตัดสินใจว่าจะทำอย่างไรกับคำขอเหล่านั้นตามตรรกะทางธุรกิจของคุณ :) แม้ว่ามันจะบอกว่า "ไม่" มันยังคงตาม REST :)
Nigel Thorne

38

คำตอบสั้น ๆ :

กฎง่ายๆ: ใช้ POST เพื่อสร้างใช้ PUT เพื่ออัปเดต

คำตอบยาว:

โพสต์:

  • POST ใช้เพื่อส่งข้อมูลไปยังเซิร์ฟเวอร์
  • มีประโยชน์เมื่อไม่ทราบ URL ของทรัพยากร

PUT:

  • PUT ใช้เพื่อโอนสถานะไปยังเซิร์ฟเวอร์
  • มีประโยชน์เมื่อทราบ URL ของทรัพยากร

คำตอบอีกต่อไป:

เพื่อให้เข้าใจได้เราต้องตั้งคำถามว่าทำไมต้องใช้ PUT ปัญหาที่ PUT พยายามแก้ไขคือ POST ไม่สามารถทำได้

จากมุมมองของสถาปัตยกรรม REST ไม่มีสิ่งใดสำคัญ เราสามารถมีชีวิตอยู่ได้โดยปราศจาก PUT เช่นกัน แต่จากมุมมองของนักพัฒนาลูกค้ามันทำให้ชีวิตของเขา / เธอง่ายขึ้นมาก

ก่อนหน้า PUT ลูกค้าไม่สามารถทราบ URL ที่เซิร์ฟเวอร์สร้างขึ้นได้โดยตรงหรือถ้าทั้งหมดนั้นได้สร้างใด ๆ หรือไม่ว่าข้อมูลที่จะส่งไปยังเซิร์ฟเวอร์นั้นได้รับการอัปเดตแล้วหรือไม่ PUT ช่วยบรรเทาอาการปวดหัวของผู้พัฒนาทั้งหมดนี้ PUT เป็น idempotent, PUT จัดการกับสภาพการแข่งขันและ PUT ให้ลูกค้าเลือก URL


3
คำตอบสั้น ๆ ของคุณอาจผิดมาก HTTP PUT สามารถทำซ้ำได้โดย HTTP proxies ดังนั้นถ้า PUT กำลังทำ SQL INSERT จริง ๆ มันอาจล้มเหลวเป็นครั้งที่สองซึ่งหมายความว่ามันจะส่งคืนผลลัพธ์ที่แตกต่างกันดังนั้นมันจะไม่ใช่ IDEMPOTENT (ซึ่งเป็นความแตกต่างระหว่าง PUT และ POST)
Kamil Tomšík

36

Ruby on Rails 4.0 จะใช้วิธี 'PATCH' แทน PUT เพื่อทำการอัพเดทบางส่วน

RFC 5789 พูดถึง PATCH (ตั้งแต่ปี 1995):

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

" Edge Rails: PATCH เป็นวิธี HTTP หลักใหม่สำหรับการอัพเดท " อธิบาย


27

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

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


2
ฉันสายไปนิดหน่อย - แต่มีคนพูดอะไรบางอย่างที่คล้ายกันในเว็บไซต์อื่นให้คลิกเพื่อฉัน หากคุณกำลังสร้างทรัพยากรและใช้รหัสที่เพิ่มโดยอัตโนมัติเนื่องจากเป็น "ตัวระบุ" แทนที่จะเป็นชื่อผู้ใช้ที่กำหนดควรเป็น POST
Ixmatus

2
นี้ไม่ถูกต้อง - ใส่ยังสามารถสร้างทรัพยากรโดยหมายถึงว่ามันมีชื่อที่ไม่เป็นที่ยอมรับตราบใดที่ในการตอบสนองผลตอบแทนเซิร์ฟเวอร์Locationส่วนหัวที่ไม่ประกอบด้วยชื่อทรัพยากรที่ยอมรับ
อีเธอร์

1
@Joshcodes อย่าลืมว่าคุณสามารถมี URI จำนวนมากที่อ้างอิงทรัพยากรพื้นฐานเดียวกัน ดังนั้นสิ่งที่อีเธอร์กล่าวคือคำแนะนำเสียงลูกค้าสามารถใส่ URL (นั่นอาจจะเป็นความหมายมากกว่าPUT /X-files/series/4/episodes/max) และเซิร์ฟเวอร์ตอบกลับด้วย URI ที่ให้ลิงค์ที่ไม่ซ้ำกันซึ่งเป็นที่ยอมรับไปยังทรัพยากรใหม่นั้น (เช่น/X-Ffiles/episodes/91)
thecoshman

@thecoshman ปัญหาคือความกังวลสำหรับโครงสร้าง URL ไม่ได้เป็นของลูกค้า การอ่านเกี่ยวกับการค้นพบตัวเอง (หรือส่วนหนึ่งของ REST) ​​อาจช่วยทำให้เรื่องนี้ชัดเจน
Joshcodes

@Joshcodes ตามตรรกะนั้นไคลเอ็นต์ไม่ควรใช้ PUT เพื่อสร้างตามที่พวกเขาไม่ควรเกี่ยวข้องกับการให้ URL ดี ... เว้นแต่เซิร์ฟเวอร์จะให้ URL แก่ PUT หากลูกค้าต้องการที่จะใส่ ... สิ่งที่ต้องการ "PUT / comments / new" และเซิร์ฟเวอร์อาจตอบสนอง "204 / comments / 234532" แต่ดูเหมือนว่าจะเล็กน้อย RPC ให้ฉันลูกค้าควรเพียงแค่โพสต์ไปยัง / แสดงความคิดเห็น ...
thecoshman

24

ในวิธีที่ง่ายมากฉันใช้ตัวอย่างของไทม์ไลน์ Facebook

กรณีที่ 1: เมื่อคุณโพสต์บางสิ่งบนไทม์ไลน์ของคุณนี่เป็นรายการใหม่ ดังนั้นในกรณีนี้พวกเขาใช้วิธี POST เพราะวิธี POST นั้นไม่ใช่ idempotent

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

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

ในบรรทัดเดียวใช้POSTเพื่อเพิ่มรายการใหม่ในฐานข้อมูลและPUTเพื่ออัปเดตบางอย่างในฐานข้อมูล


4
หากความคิดเห็นเป็นวัตถุที่มีคุณสมบัติเช่นรหัสผู้ใช้วันที่สร้างข้อความแสดงความคิดเห็น ฯลฯ และในขณะที่มีการแก้ไขเฉพาะข้อความความคิดเห็นเท่านั้นที่จะได้รับการอัปเดต PATCH ควรทำที่นี่หรือไม่
Habeeb Perwad

PUT ถูกใช้โดย FB เพื่ออัพเดตความคิดเห็นเนื่องจากทรัพยากรที่มีอยู่กำลังถูกอัพเดตและนั่นคือสิ่งที่ PUT ทำ (อัพเดตทรัพยากร) PUT นั้นเป็น idempotent ตรงกันข้ามกับ POST HTTP verb ที่เป็น idempotent ส่งผลกระทบต่อการจัดการข้อผิดพลาด แต่ไม่ได้บอกการใช้งาน ดูคำตอบของฉันสำหรับคำอธิบายรายละเอียดเพิ่มเติม: stackoverflow.com/questions/630453/put-vs-post-in-rest/
......

21

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

ตัวอย่างเช่นคุณอาจไม่ควรสร้างธุรกรรมบัตรเครดิตด้วย POST

หากคุณมี URI ที่สร้างขึ้นอัตโนมัติบนทรัพยากรของคุณคุณยังสามารถใช้ PUT ได้โดยส่ง URI ที่สร้างขึ้น (ชี้ไปที่ทรัพยากรที่ว่างเปล่า) ไปยังลูกค้า

ข้อควรพิจารณาอื่น ๆ :

  • POST ทำให้สำเนาที่เก็บไว้ของทรัพยากรที่เก็บไว้ทั้งหมดมีความไม่ถูกต้อง (ความสอดคล้องที่ดีขึ้น)
  • การตอบกลับ PUT ไม่สามารถแคชได้ในขณะที่โพสต์ POST (ต้องมีที่ตั้งเนื้อหาและการหมดอายุ)
  • PUT รองรับน้อยกว่าเช่น Java ME, เบราว์เซอร์รุ่นเก่า, ไฟร์วอลล์

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

โดยทั่วไปผู้ใช้จะไม่สามารถลองดำเนินการ POST ได้อย่างปลอดภัยเนื่องจากการดำเนินการ POST ไม่รับประกันว่าการดำเนินการสองอย่างจะมีผลเช่นเดียวกัน คำว่า "ID" ไม่มีส่วนเกี่ยวข้องกับ HTTP URI จะระบุทรัพยากร
Hans Malherbe

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

เรียบหัวกับผนัง HTTP ไม่มีวิธีแก้ปัญหาความน่าเชื่อถือและไม่เข้าใจอย่างถ่องแท้ไม่พูดถึงมากและไม่ได้รับการตอบสนองในเว็บแอพพลิเคชันส่วนใหญ่ @Joshcodes ฉันมีคำตอบสำหรับคำถามนี้ ฉันเห็นด้วยกับฮันส์เป็นหลัก มีปัญหา
bbsimonbb

@bbsimonbb, HTTP มีชุดการตอบสนองข้อผิดพลาดที่มีประสิทธิภาพและมีเอกสารครบถ้วน คำตอบของฉันสำหรับคำถามนี้ ( stackoverflow.com/questions/630453/put-vs-post-in-rest/ ...... ) ครอบคลุมถึงวิธีการใช้ http ตามข้อกำหนดเพื่อให้เกิดความมั่นคง
Joshcodes

17

ผู้อ่านใหม่ในหัวข้อนี้จะได้รับการพูดคุยอย่างไม่มีที่สิ้นสุดเกี่ยวกับสิ่งที่คุณควรทำและการไม่มีบทเรียนจากประสบการณ์ ความจริงที่ว่า REST นั้น "ชอบ" มากกว่า SOAP คือฉันคิดว่าการเรียนรู้ระดับสูงจากประสบการณ์ แต่ความดีที่เราต้องก้าวหน้าไปจากที่นั่น? ปี 2559 วิทยานิพนธ์ของ Roy อยู่ในปี 2000 เราพัฒนาอะไรบ้าง มันสนุกไหม? มันง่ายที่จะรวมกับ? ให้การช่วยเหลือ? มันจะรองรับการเพิ่มขึ้นของสมาร์ทโฟนและการเชื่อมต่อมือถือที่ไม่สม่ำเสมอหรือไม่?

เครือข่ายชีวิตจริงไม่น่าเชื่อถือ ขอหมดเวลา การเชื่อมต่อถูกรีเซ็ต เครือข่ายลดจำนวนครั้งต่อวันหรือหลายชั่วโมง รถไฟเข้าสู่อุโมงค์ด้วยผู้ใช้มือถือในต่างประเทศ สำหรับการร้องขอใด ๆ ที่ได้รับ (ตามที่ได้รับการยอมรับเป็นครั้งคราวในการสนทนาทั้งหมด) คำขอสามารถตกลงไปในน้ำในทางของมันหรือการตอบสนองอาจตกอยู่ในน้ำในทางกลับ ในเงื่อนไขเหล่านี้การออกคำขอ PUT, POST และ DELETE โดยตรงกับแหล่งข้อมูลสำคัญทำให้ฉันเป็นคนที่โหดร้ายและไร้เดียงสาอยู่เสมอ

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

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

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

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

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

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

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

ก่อนที่จะบอกฉันว่านี่ไม่ใช่ RESTful โปรดพิจารณาวิธีการมากมายที่หลักการ REST ได้รับการเคารพ ลูกค้าไม่ได้สร้าง URL API ยังคงค้นหาได้แม้ว่าจะมีการเปลี่ยนแปลงเล็กน้อยในความหมาย ใช้คำกริยา HTTP อย่างเหมาะสม หากคุณคิดว่านี่เป็นการเปลี่ยนแปลงครั้งใหญ่ที่จะนำไปปฏิบัติฉันสามารถบอกคุณได้จากประสบการณ์ที่ไม่ใช่

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


1
การจัดเก็บการตอบสนองจะไม่เหมือนการรักษาเซสชันหรือไม่? ซึ่งจะทำให้เกิดปัญหาการปรับขนาด (แนวนอน)
Saurabh Harwande

17

นอกเหนือจากความแตกต่างที่ผู้อื่นแนะนำฉันต้องการเพิ่มอีกหนึ่งรายการ

ในวิธีการโพสต์คุณสามารถส่งพารามิเตอร์ร่างกายมาform-data

ในวิธีPUTคุณจะต้องส่งพารามิเตอร์ร่างกายx-www-form-urlencoded

หัวข้อ Content-Type:application/x-www-form-urlencoded

ตามนี้คุณไม่สามารถส่งไฟล์หรือข้อมูลหลายส่วนในวิธีการPUT

แก้ไข

ประเภทเนื้อหา "application / x-www-form-urlencoded" นั้นไม่มีประสิทธิภาพในการส่งข้อมูลไบนารีหรือข้อความจำนวนมากที่มีอักขระที่ไม่ใช่ ASCII ควรใช้ชนิดเนื้อหา "multipart / form-data" สำหรับการส่งแบบฟอร์มที่มีไฟล์ข้อมูลที่ไม่ใช่ ASCII และข้อมูลไบนารี

ซึ่งหมายความว่าหากคุณต้องส่ง

ไฟล์ข้อมูลที่ไม่ใช่ ASCII และข้อมูลไบนารี

คุณควรใช้วิธีการPOST


3
ทำไมสิ่งนี้ถึงไม่ถูกโหวต หากเป็นจริงนี่คือความแตกต่างที่สำคัญไม่ใช่หรือ?
Iofacture

2
ฉันประสบเมื่อใช้งาน API สำหรับการอัปเดตโปรไฟล์ซึ่งรวมถึงการอัปโหลดโปรไฟล์ผู้ใช้ จากนั้นฉันทดสอบกับบุรุษไปรษณีย์, Ajax, PHP curl และ laravel 5.6 เป็นแบ็กเอนด์
Rohit Dhiman

14

ดูเหมือนจะมีความสับสนอยู่เสมอว่าจะใช้ HTTP POST กับวิธี HTTP PUT สำหรับบริการ REST เมื่อใด นักพัฒนาส่วนใหญ่จะพยายามเชื่อมโยงการดำเนินงาน CRUD โดยตรงกับวิธีการ HTTP ฉันจะยืนยันว่าสิ่งนี้ไม่ถูกต้องและไม่มีใครสามารถเชื่อมโยงแนวคิด CRUD กับวิธี HTTP ได้ นั่นคือ:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

เป็นจริงที่ R (etrieve) และ D (elete) ของการดำเนินการ CRUD สามารถถูกแมปโดยตรงกับวิธี HTTP ได้รับและลบตามลำดับ อย่างไรก็ตามความสับสนอยู่ในการดำเนินการ C (reate) และ U (update) ในบางกรณีหนึ่งสามารถใช้ PUT สำหรับการสร้างในขณะที่ในกรณีอื่น ๆ จะต้องมี POST ความกำกวมอยู่ในนิยามของวิธี HTTP PUT เทียบกับวิธี HTTP POST

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

จากนิยามของ idempotent ข้างต้นการใช้ของฉันในการใช้วิธี HTTP PUT กับการใช้วิธี HTTP POST สำหรับบริการ REST คือ: ใช้วิธี HTTP PUT เมื่อ:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

ในทั้งสองกรณีการดำเนินการเหล่านี้สามารถทำได้หลายครั้งด้วยผลลัพธ์เดียวกัน นั่นคือทรัพยากรจะไม่ถูกเปลี่ยนแปลงโดยการร้องขอการดำเนินการมากกว่าหนึ่งครั้ง ดังนั้นการดำเนิน idempotent ที่แท้จริง ใช้วิธี HTTP POST เมื่อ:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

ข้อสรุป

อย่าเชื่อมโยงโดยตรงและแมปการดำเนินการ CRUD กับวิธี HTTP สำหรับบริการ REST การใช้วิธี HTTP PUT กับวิธี HTTP POST ควรเป็นไปตามลักษณะของ idempotent ของการดำเนินการนั้น นั่นคือถ้าการดำเนินการ idempotent แล้วใช้วิธีการ HTTP PUT หากการดำเนินการไม่ใช่ idempotent ให้ใช้วิธี HTTP POST


2
Update => HTTP POST: POST ไม่ได้มีไว้สำหรับอัปเดต
Premraj

@premraj คุณตั้งสมมติฐานว่า Burhan กำลังบอกคุณไม่ให้ทำ กล่าวคือคุณกำลังสร้าง CRUD, REST และ HTTP หากคุณอ่าน RFC 7231 ซึ่งมีการกำหนดสิ่งเหล่านี้คุณจะพบว่าในโปรโตคอล HTTP นิยามของ POST ช่วยให้สามารถอัปเดตได้อย่างแน่นอน มันเป็นเพียงข้อ จำกัด ของ REST ที่พูดเป็นอย่างอื่น
IAM_AL_X

13

เซิร์ฟเวอร์ต้นทางสามารถสร้างทรัพยากรด้วย URI นั้น

ดังนั้นคุณใช้ POST และอาจ แต่ไม่จำเป็นต้อง PUT สำหรับการสร้างทรัพยากร คุณไม่ต้องสนับสนุนทั้งคู่ สำหรับฉันโพสต์สมบูรณ์พอ ดังนั้นจึงเป็นการตัดสินใจออกแบบ

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


ฉันคิดว่าคุณสามารถจัดการให้เป็นหนึ่งในตัวอย่างที่ดีของวิธีใช้ PUT ได้ดีมาก
thecoshman

12

ฉันจะลงจอดด้วยสิ่งต่อไปนี้:

PUT หมายถึงทรัพยากรที่ระบุโดย URI ในกรณีนี้คุณกำลังอัปเดต มันเป็นส่วนหนึ่งของคำกริยาทั้งสามที่อ้างถึงทรัพยากร - ลบและรับอีกสอง

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


เนื่องจาก PUT และ GET และ DELETE อ้างถึงทรัพยากรจึงเป็นไปตามนิยาม idempotent

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

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


แก้ไข: อีกสิ่งหนึ่ง - PUT สามารถสร้างได้ แต่ถ้าเป็นเช่นนั้น ID จะต้องเป็น ID ธรรมชาติ - AKA ที่อยู่อีเมล ด้วยวิธีนี้เมื่อคุณใส่สองครั้งพัตที่สองคือการอัพเดตครั้งแรก นี้จะทำให้มันidempotent

หาก ID ถูกสร้างขึ้น (เช่นรหัสพนักงานใหม่) ดังนั้น PUT ตัวที่สองที่มี URL เดียวกันจะสร้างระเบียนใหม่ซึ่งละเมิดกฎ idempotent ในกรณีนี้คำกริยาจะเป็น POST และข้อความ (ไม่ใช่ทรัพยากร) คือการสร้างทรัพยากรโดยใช้ค่าที่กำหนดไว้ในข้อความนี้


9

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

ฉันจะอธิบายถึงอนุสัญญาที่ฉันคิดว่าใช้กันอย่างแพร่หลายและมีประโยชน์มากที่สุด:

เมื่อคุณใส่ทรัพยากรที่ URL ใด ๆ สิ่งที่เกิดขึ้นคือมันควรได้รับการบันทึกไว้ที่ URL นั้นหรือสิ่งอื่น ๆ ที่อยู่ในบรรทัดเหล่านั้น

เมื่อคุณโพสต์ไปยังทรัพยากรที่ URL เฉพาะมักจะโพสต์ชิ้นส่วนของข้อมูลที่เกี่ยวข้องกับ URL นั้น นี่หมายความว่ามีทรัพยากรที่ URL อยู่แล้ว

ตัวอย่างเช่นเมื่อคุณต้องการสร้างกระแสใหม่คุณสามารถใส่ลงใน URL ได้ แต่เมื่อคุณต้องการโพสต์ข้อความไปยังสตรีมที่มีอยู่คุณโพสต์ไปที่ URL

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

อย่างไรก็ตามโปรดทราบว่าไม่ใช่ทุกเบราว์เซอร์ที่ทันสมัยรองรับกริยา HTTP นอกเหนือจาก GET หรือ POST


สิ่งที่คุณอธิบาย POST ตามที่เป็นจริงว่า PATCH ควรประพฤติอย่างไร POST ควรจะหมายถึงบางสิ่งที่คล้ายกับ "ผนวก" เช่นเดียวกับใน "โพสต์ไปยังรายชื่อผู้รับจดหมาย"
Alexander Torstling

8

ส่วนใหญ่คุณจะใช้พวกเขาเช่นนี้:

  • โพสต์ทรัพยากรลงไปในคอลเลกชัน
  • PUTทรัพยากรระบุคอลเลกชัน /: รหัส

ตัวอย่างเช่น:

  • โพสต์ / รายการ
  • วาง / รายการ / 1234

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

โปรดทราบว่า POST "สร้าง" องค์ประกอบใหม่ในคอลเลกชันและ PUT "แทนที่" องค์ประกอบที่ URL ที่กำหนด แต่เป็นวิธีปฏิบัติทั่วไปในการใช้ PUT สำหรับการแก้ไขบางส่วนกล่าวคือใช้เพื่ออัปเดตทรัพยากรที่มีอยู่และ ปรับเปลี่ยนเฉพาะฟิลด์ที่รวมอยู่ในเนื้อหา (ละเว้นฟิลด์อื่น) นี่เป็นเทคนิคที่ไม่ถูกต้องหากคุณต้องการที่จะพักที่ดีที่สุด PUT ควรแทนที่ทรัพยากรทั้งหมดและคุณควรใช้ PATCH สำหรับการอัพเดทบางส่วน ฉันเองไม่สนใจเท่าที่พฤติกรรมจะชัดเจนและสอดคล้องกับจุดสิ้นสุด API ทั้งหมดของคุณ

โปรดจำไว้ว่า REST เป็นชุดของข้อตกลงและแนวทางเพื่อให้ API ของคุณง่าย หากคุณจบลงด้วยการแก้ปัญหาที่ซับซ้อนเพียงเพื่อทำเครื่องหมายในช่อง "RESTfull" คุณจะต้องทำตามวัตถุประสงค์;)


7

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

ขอให้ชัดเจนและตรงนี้ หากคุณเป็นนักพัฒนา. NET ที่ทำงานกับ Web API ข้อเท็จจริงคือ (จากเอกสาร Microsoft API), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-support-crud-Operations :

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

แน่ใจว่าคุณ "สามารถ" ใช้ "โพสต์" เพื่ออัปเดต แต่เพียงทำตามอนุสัญญาที่วางไว้สำหรับคุณด้วยกรอบงานที่คุณกำหนด ในกรณีของฉันมันคือ. NET / Web API ดังนั้นPUT สำหรับ UPDATEจึงไม่มีข้อโต้แย้ง

ฉันหวังว่านี่จะช่วยให้นักพัฒนาซอฟต์แวร์ของ Microsoft ที่อ่านความคิดเห็นทั้งหมดกับลิงก์เว็บไซต์ Amazon และ Sun / Java


7

นี่เป็นกฎง่ายๆ:

ควรใช้PUTไปยัง URL เพื่ออัปเดตหรือสร้างทรัพยากรที่สามารถอยู่ที่ URL นั้น

ควรใช้POSTไปยัง URL เพื่ออัปเดตหรือสร้างทรัพยากรซึ่งอยู่ที่ URL อื่น ๆ ("ผู้ใต้บังคับบัญชา") หรือไม่สามารถหาตำแหน่งผ่าน HTTP


1
PUT ไม่ได้มีไว้สำหรับอัพเดต แต่มีไว้สำหรับแทนที่โปรดทราบว่าในการสร้างคุณกำลังแทนที่สิ่งใด ๆ POST ไม่ได้มีไว้สำหรับอัพเดตในรูปแบบใด ๆ
thecoshman

2
http spec บอกอย่างนั้นหรือเปล่า? หรือคุณกำลังแสดงความคิดเห็นของคุณในสิ่งอื่น?
Adam Griffiths

มันเป็นเพียงแค่สามัญสำนึกวิธีที่คุณอัปเดตบางสิ่งบางอย่างเมื่อคุณไม่รู้ว่าคุณกำลังปรับปรุงอะไรอยู่ POST สำหรับสร้างทรัพยากรใหม่
thecoshman

2
thecoshman - คุณกำลังใช้ความหมายที่ไม่เหมาะสมที่นี่ - การแทนที่สามารถเป็นการอัปเดตหากเป็นทรัพยากรเดียวกันที่มีความแตกต่างกันเล็กน้อย การแทนที่ใช้ได้สำหรับการวางหากการแทนที่ถูกใช้เพื่อเปลี่ยนรีซอร์สเดียวกัน การแทนที่ด้วยทรัพยากรใหม่และที่แตกต่างกันนั้นไม่ถูกต้อง (ลบเก่าและเพิ่มใหม่?) โดยเฉพาะอย่างยิ่งหากทรัพยากร 'ใหม่' ไม่มีรหัสธรรมชาติ POST, OTOH เป็นสิ่งที่สามารถสร้างอัปเดตแทนที่และลบ - การใช้โพสต์ขึ้นอยู่กับว่ามีข้อความที่จะตีความเช่น 'ใช้ส่วนลด' ซึ่งอาจเปลี่ยนแปลงหรือไม่ขึ้นอยู่กับทรัพยากร ตรรกะ.
เจอราร์ดโอนีล

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

6

หากคุณคุ้นเคยกับการทำงานของฐานข้อมูล

  1. เลือก
  2. แทรก
  3. ปรับปรุง
  4. ลบ
  5. ผสาน (อัปเดตหากมีอยู่แล้วแทรกอื่น)

ฉันใช้PUTสำหรับผสานและอัปเดตเช่นการดำเนินการและใช้POSTสำหรับการแทรก


5

ในทางปฏิบัติ POST ทำงานได้ดีสำหรับการสร้างทรัพยากร URL ของทรัพยากรที่สร้างขึ้นใหม่ควรส่งคืนในหัวข้อการตอบสนองตำแหน่ง ควรใช้ PUT เพื่ออัปเดตทรัพยากรอย่างสมบูรณ์ โปรดเข้าใจว่าสิ่งเหล่านี้เป็นแนวทางปฏิบัติที่ดีที่สุดเมื่อออกแบบ RESTful API ข้อมูลจำเพาะ HTTP เช่นนี้ไม่ได้ จำกัด การใช้ PUT / POST ด้วยข้อ จำกัด เล็กน้อยสำหรับการสร้าง / อัปเดตทรัพยากร ลองดูที่http://techoctave.com/c7/posts/71-twitter-rest-api-dissectedซึ่งสรุปแนวทางปฏิบัติที่ดีที่สุด


ส่วนใหญ่จากการอ่านเสียงทั้งหมดนี้คุณดูเหมือนจะอยู่บนลูกบอล ฉันจะบอกว่าเราควรอ้างถึง PUT เป็นวิธีการแทนที่มากกว่าการสร้าง / ปรับปรุง ฉันคิดว่ามันอธิบายได้ดีกว่าในสิ่งที่มันทำ
thecoshman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.