it-swarm.com.ru

PUT против POST в REST

Согласно спецификации HTTP/1.1:

Метод POST используется для запроса, чтобы сервер Origin принял сущность, заключенную в запросе, в качестве нового подчиненного ресурса, идентифицированного Request-URI в Request-Line

Другими словами, POST используется для создания.

Метод PUT запрашивает, чтобы вложенная сущность была сохранена под предоставленным Request-URI. Если Request-URI ссылается на уже существующий ресурс, вложенный объект СЛЕДУЕТ рассматривать как измененную версию объекта, находящегося на сервере Origin. Если Request-URI не указывает на существующий ресурс и этот URI может быть определен как новый ресурс запрашивающим пользовательским агентом, сервер Origin может создать ресурс с этим URI. "

То есть PUT используется для создания или обновления.

Итак, какой из них следует использовать для создания ресурса? Или нужно поддерживать оба?

4981
alex

Общая оценка:

И PUT, и POST можно использовать для создания.

Вы должны спросить "для чего вы выполняете действие?" чтобы отличить то, что вы должны использовать. Предположим, вы разрабатываете API для вопросов. Если вы хотите использовать POST, вы должны сделать это со списком вопросов. Если вы хотите использовать PUT, вы должны сделать это для конкретного вопроса.

Могут быть использованы оба варианта, поэтому какой из них мне следует использовать в моем дизайне RESTful:

Вам не нужно поддерживать PUT и POST.

Что используется, остается за вами. Но просто не забудьте использовать правильный в зависимости от того, на какой объект вы ссылаетесь в запросе.

Некоторые соображения:

  • Вы называете свои объекты URL, которые вы создаете явно, или позволяете серверу решать? Если вы называете их, используйте PUT. Если вы позволите серверу решить, используйте POST.
  • PUT идемпотентен, поэтому, если вы поместите объект дважды, это не даст никакого эффекта. Это свойство Nice, поэтому я бы использовал PUT, когда это возможно.
  • Вы можете обновить или создать ресурс с PUT с тем же URL объекта
  • С POST вы можете получать 2 запроса одновременно, внося изменения в URL, и они могут обновлять различные части объекта.

Пример:

я написал следующее как часть другого ответа на SO относительно этого :

POST:

Используется для изменения и обновления ресурса

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/
3929
Brian R. Bondy

Вы можете найти утверждения в Интернете, которые говорят

Ни один не совсем прав.


Лучше выбрать между PUT и POST на основе идемпотентность действия.

PUT подразумевает размещение ресурса - полную замену всего, что доступно по данному URL, на другое. По определению, PUT является идемпотентом. Делайте это столько раз, сколько хотите, и результат тот же. x=5 является идемпотентом. Вы можете положить ресурс независимо от того, существует ли он ранее или нет (например, создать или обновить)!

POST обновляет ресурс, добавляет вспомогательный ресурс или вызывает изменение. POST не идемпотентен, так как x++ не идемпотентен.


По этому аргументу PUT предназначен для создания, когда вы знаете URL-адрес того, что вы создадите. POST можно использовать для создания, когда вы знаете URL "фабрики" или менеджера для категории вещей, которые вы хотите создать.

так:

POST /expense-report

или же:

PUT  /expense-report/10929
2071
Cheeso
  • POST на URL создает дочерний ресурс в определенный сервером URL.
  • ПОСТАВИТЬ на URL создает/заменяет ресурс полностью на определенном клиентом URL.
  • ПАТЧ к 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 являются идемпотентными .

RFC звучит так:

Принципиальное различие между запросами POST и ​​PUT отражается в различном значении Request-URI. URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенную сущность. Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, принимающим аннотации. Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к какому-либо другому ресурсу. Если сервер желает, чтобы запрос был применен к другому URI,

Примечание: PUT в основном использовался для обновления ресурсов (путем их полной замены), но в последнее время наблюдается движение к использованию PATCH для обновления существующих ресурсов, as PUT указывает, что он заменяет весь ресурс. RFC 5789.

Обновление 2018 : есть случай, чтобы избежать PUT. Смотрите "ОТДЫХ без ПУТА"

С техникой "REST без PUT" идея заключается в том, что потребители вынуждены публиковать новые "несущественные" ресурсы запросов. Как обсуждалось ранее, изменение почтового адреса клиента - это POST на новый ресурс "ChangeOfAddress", а не PUT ресурса "Клиент" с другим значением поля почтового адреса.

взято из REST API Design - Моделирование ресурсов Пракаша Субраманиама из Thoughtworks

Это вынуждает API избегать проблем с переходом состояний при обновлении одного ресурса несколькими клиентами и более точно согласуется с источником событий и CQRS. Когда работа выполняется асинхронно, установка POST и ожидание ее применения представляется целесообразной.

651
Nigel Thorne

Резюме:

Создайте:

Можно выполнить как PUT, так и POST следующим образом:

ПОЛОЖИЛ

Создает новый ресурс с newResourceId в качестве идентификатора в URI/resources или коллекции ,.

PUT /resources/<newResourceId> HTTP/1.1 

POST

Создает A новый ресурс в URI/resources или коллекцию . Обычно идентификатор возвращается сервером.

POST /resources HTTP/1.1

Обновление:

Можно только выполнить с PUT следующим образом:

ПОЛОЖИЛ

Обновляет ресурс с существующим ID ресурса в качестве идентификатора в URI/resources или коллекции .

PUT /resources/<existingResourceId> HTTP/1.1

Объяснение:

При работе с REST и 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

вы публикуете нового пользователя в коллекции users .

Если вы продолжите и попробуете что-то вроде этого:

POST /users/john HTTP/1.1

это будет работать, но семантически вы говорите, что хотите добавить ресурс в коллекцию john под коллекция пользователей .

Когда вы используете PUT, вы ссылаетесь на ресурс или отдельный элемент, возможно, внутри коллекции . Поэтому, когда вы говорите:

PUT /users/john HTTP/1.1

вы сообщаете серверу об обновлении или создаете, если он не существует, ресурс john под коллекция пользователей .

Spec:

Позвольте мне выделить некоторые важные части спецификации:

POST

Метод POST используется для запроса, чтобы сервер Origin принял сущность, заключенную в запросе, как новый подчиненный ресурс, указанный в Request-URI в строке запроса

Следовательно, создает новый ресурс в коллекции .

ПОЛОЖИЛ

Метод PUT запрашивает, чтобы вложенная сущность была сохранена под предоставленным Request-URI. Если Request-URI ссылается на уже существующий ресурс, вложенную сущность СЛЕДУЕТ рассматривать как модифицированную версию той, которая находится на сервере Origin , Если Request-URI не указывает на существующий ресурс, и этот URI способен быть определенным как новый ресурс запрашивающего агента пользователя, сервер Origin может создать ресурс с этим URI. "

Следовательно, создавайте или обновляйте, основываясь на существовании ресурса .

Ссылка:

191
7hi4g0

Я хотел бы добавить мой "прагматичный" совет. Используйте PUT, когда вы знаете "идентификатор", по которому можно получить сохраняемый объект. Использование PUT не будет работать слишком хорошо, если вам понадобится, скажем, идентификатор, сгенерированный базой данных, который будет возвращен вам для будущих поисков или обновлений.

Итак: Чтобы сохранить существующего пользователя или пользователя, для которого клиент генерирует идентификатор, и было подтверждено, что идентификатор является уникальным:

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
170
ThaDon

POST означает "создать новый", как в "Вот вход для создания пользователя, создайте его для меня".

PUT означает "вставить, заменить, если он уже существует", как в "Вот данные для пользователя 5".

Вы POST на example.com/users, поскольку вы еще не знаете URL-адрес пользователя, вы хотите, чтобы сервер его создал.

Вы кладете на example.com/users/id, поскольку хотите заменить/создать определенного пользователя.

Двойная публикация с одинаковыми данными означает создание двух идентичных пользователей с разными идентификаторами. PUT дважды с одними и теми же данными создает пользователя первым и обновляет его до того же состояния во второй раз (без изменений). Поскольку после PUT вы получаете одно и то же состояние, независимо от того, сколько раз вы его выполняете, оно называется "одинаково мощным" каждый раз - идемпотентным. Это полезно для автоматической повторной попытки запросов. Нет больше "вы уверены, что хотите отправить", когда вы нажимаете кнопку "Назад" в браузере.

Общий совет - использовать POST, когда вам нужно, чтобы сервер контролировал генерацию URL ваших ресурсов. В противном случае используйте PUT. Предпочитаю ставить над постом.

163
Alexander Torstling

Используйте POST для создания и PUT для обновления. Вот как это делает Ruby на Rails.

PUT    /items/1      #=> update
POST   /items        #=> create
121
Tim Sullivan

Оба используются для передачи данных между клиентом и сервером, но между ними есть тонкие различия:

Enter image description here

Аналогия:

  • PUT т.е. взять и поставить , где это было.
  • POST as отправить почту в почтовом офисе.

enter image description here

Социальная сеть/Сетевая аналогия:

  • Сообщение в социальных сетях: когда мы публикуем сообщение, оно создает новое сообщение.
  • Поставьте (т.е. отредактируйте) для сообщения, которое мы уже опубликовали.
96
Premraj

REST - это очень концепция высокого уровня. На самом деле, он даже не упоминает HTTP вообще!

Если у вас есть какие-либо сомнения относительно того, как реализовать REST в HTTP, вы всегда можете взглянуть на спецификацию Atom Publication Protocol (AtomPub)) . AtomPub - это стандарт для написания веб-сервисов RESTful с HTTP, который был разработан многими светилами HTTP и REST при некотором вкладе Роя Филдинга, изобретателя REST и ​​(со) изобретателя Сам HTTP.

На самом деле, вы даже можете использовать AtomPub напрямую. Хотя он вышел из сообщества блогеров, он никоим образом не ограничен блогами: это общий протокол для RESTful взаимодействия с произвольными (вложенными) коллекциями произвольных ресурсов через HTTP. Если вы можете представить свое приложение как вложенную коллекцию ресурсов, то вы можете просто использовать AtomPub и не беспокоиться о том, использовать ли PUT или POST, какие коды состояния HTTP возвращать и все эти подробности.

Вот что AtomPub говорит о создании ресурса (раздел 9.2):

Чтобы добавить участников в коллекцию, клиенты отправляют POST запросы на URI коллекции.

65
Jörg W Mittag

Решение о том, использовать ли PUT или POST для создания ресурса на сервере с HTTP + REST API, зависит от того, кому принадлежит URL структура. Когда клиент знает или принимает участие в определении, структура URL является ненужной связью, сродни нежелательным связям, возникающим из SOA. Экранирование типов соединений является причиной того, что REST так популярен. Поэтому правильный метод для использования - это POST. Есть исключения из этого правила, и они возникают, когда клиент желает сохранить контроль над структурой расположения ресурсы, которые он развертывает. Это редко и, вероятно, означает, что что-то еще не так.

На этом этапе некоторые люди утверждают, что если используются RESTful-URL , клиент знает URL-адрес ресурса и, следовательно, PUT является приемлемым. В конце концов, именно поэтому канонические, нормализованные, Ruby on Rails, Django URL-адреса важны, посмотрите на API Twitter… бла-бла-бла. Эти люди должны понимать , что не существует такой вещи, как Restful-URL , и что сам Рой Филдинг утверждает, что :

API REST не должен определять фиксированные имена ресурсов или иерархии (очевидная связь клиента и сервера). Серверы должны иметь свободу управления своим собственным пространством имен. Вместо этого позвольте серверам инструктировать клиентов о том, как создавать соответствующие URI, например, в HTML-формах и шаблонах URI, определяя эти инструкции в типах мультимедиа и ссылочных отношениях. [Ошибка здесь подразумевает, что клиенты принимают структуру ресурса из-за внеполосной информации, такой как специфичный для области стандарт, который является ориентированным на данные эквивалентом функциональной связи RPC].

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

Идея RESTful-URL на самом деле является нарушением REST, поскольку сервер отвечает за структуру URL и должен свободно решать, как его использовать. это, чтобы избежать сцепления. Если это вас смущает, читайте о значении самопознания для разработки API.

Использование POST для создания ресурсов сопряжено с соображениями проектирования, поскольку POST не идемпотентно. Это означает, что повторение POST несколько раз не гарантирует одинаковое поведение каждый раз. Это пугает людей использованием PUT для создания ресурсов, когда они не должны. Они знают, что это неправильно (POST для CREATE), но они делают это в любом случае, потому что они не не знаю, как решить эту проблему. Эта проблема проявляется в следующей ситуации:

  1. Клиент POST новый ресурс для сервера.
  2. Сервер обрабатывает запрос и отправляет ответ.
  3. Клиент никогда не получает ответ.
  4. Сервер не знает, клиент не получил ответ.
  5. У клиента нет URL-адреса для ресурса (поэтому PUT не является опцией) и повторяется POST.
  6. ПОСТ не идемпотент, а сервер…

На шестом этапе люди обычно не понимают, что делать. Тем не менее, нет никаких причин для создания этой проблемы. Вместо этого HTTP можно использовать, как указано в RFC 2616 , и сервер отвечает:

10.4.10 409 Конфликт

Запрос не может быть выполнен из-за конфликта с текущим состоянием ресурса. Этот код разрешен только в ситуациях, когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос. Тело ответа ДОЛЖНО включать достаточно

информация для пользователя, чтобы распознать источник конфликта. В идеале, объект ответа должен включать в себя достаточно информации, чтобы пользователь или пользовательский агент мог решить проблему; однако это может быть невозможно и не требуется.

Конфликты чаще всего возникают в ответ на запрос PUT. Например, если использовалось управление версиями, а объект PUT включал изменения в ресурсе, которые конфликтуют с ресурсами, сделанными ранее (сторонним) запросом, сервер может использовать ответ 409, чтобы указать, что он не может выполнить запрос , В этом случае объект ответа, скорее всего, будет содержать список различий между двумя версиями в формате, определяемом типом содержимого ответа.

Ответ с кодом состояния 409 Конфликт является правильным решением, потому что :

  • Выполнение POST данных, идентификатор которых совпадает с ресурсом, уже находящимся в системе, является "конфликтом с текущим состоянием ресурса".
  • Поскольку важная часть для клиента, чтобы понять, сервер имеет ресурс и принять соответствующие меры. Это "ситуация (ситуации), когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос".
  • Ответ, который содержит URL-адрес ресурса с конфликтующим идентификатором и соответствующие предварительные условия для ресурса, предоставит "достаточно информации для пользователя или пользовательского агента для решения проблемы", что является идеальным случаем в соответствии с RFC 2616.

Обновление на основе выпуска RFC 7231 для замены 2616

RFC 7231 предназначен для замены 2616 и в Раздел 4.3. описывает следующие возможные ответы для POST

Если результат обработки POST будет эквивалентен представлению существующего ресурса, сервер Origin МОЖЕТ перенаправить пользовательский агент на этот ресурс, отправив ответ 303 (см. Раздел Другое) с идентификатором существующего ресурса в поле Местоположение. Это дает преимущества предоставления пользовательскому агенту идентификатора ресурса и передачи представления с помощью метода, более поддающегося совместному кэшированию, хотя за счет дополнительного запроса, если пользовательский агент еще не имеет кэшированное представление.

Теперь может возникнуть соблазн просто вернуть 303 в случае повторения POST. Однако обратное верно. Возврат 303 имеет смысл, только если несколько запросов на создание (создание разных ресурсов) возвращают один и тот же контент. В качестве примера можно привести "спасибо за отправку сообщения с запросом", которое клиент не должен повторно загружать каждый раз. RFC 7231 по-прежнему утверждает в разделе 4.2.2, что POST не должен быть идемпотентом, и продолжает утверждать, что POST следует использовать для создания.

Для получения дополнительной информации об этом, прочитайте это статья .

59
Joshcodes

Мне нравится этот совет из определение PUT в RFC 2616 :

Принципиальное различие между запросами POST и ​​PUT отражается в различном значении Request-URI. URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенную сущность. Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, принимающим аннотации. Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к какому-либо другому ресурсу.

Это согласуется с другим советом, заключающимся в том, что PUT лучше всего применять к ресурсам, которые уже имеют имя, а POST подходит для создания нового объекта в существующем ресурсе (и позволяет серверу присвоить ему имя).

Я интерпретирую это и требования идемпотентности к PUT, чтобы означать, что:

  • POST хорош для создания новых объектов в коллекции (и для создания не нужно быть идемпотентом)
  • PUT хорош для обновления существующих объектов (и обновление должно быть идемпотентным)
  • POST также может использоваться для неидемпотентных обновлений существующих объектов (особенно для изменения части объекта без указания всей цели - если вы об этом думаете, создание нового члена коллекции на самом деле является частным случаем такого рода обновление, с точки зрения коллекции)
  • PUT также может использоваться для создания, если и только если вы разрешите клиенту называть ресурс. Но поскольку REST клиенты не должны делать предположений относительно структуры URL, это не так, как задумано.
52
metamatt

Короче:

PUT является идемпотентом, где состояние ресурса будет одинаковым, если одна и та же операция выполняется один или несколько раз.

POST неидемпотентно, где состояние ресурса может отличаться, если операция выполняется несколько раз по сравнению с выполнением одного раза.

Аналогия с запросом к базе данных

ПОЛОЖИТЬ Вы можете подумать о похожем на "ОБНОВЛЕНИЕ СТУДЕНЧЕСКОГО SET адрес" = "abc", где id = "123";

POST Вы можете придумать что-то вроде "INSERT INTO STUDENT (name, address) VALUES (" abc "," xyzzz ");

Идентификатор студента генерируется автоматически.

С PUT, если один и тот же запрос выполняется несколько раз или один раз, состояние таблицы STUDENT остается неизменным.

В случае POST, если один и тот же запрос выполняется несколько раз, в базе данных создается несколько записей Стьюдента, и состояние базы данных изменяется при каждом выполнении запроса INSERT.

ПРИМЕЧАНИЕ: PUT требуется местоположение ресурса (уже ресурс), для которого должно происходить обновление, тогда как POST не требует этого. Следовательно, интуитивно POST предназначено для создания нового ресурса, а PUT необходим для обновления уже существующего ресурса.

Некоторые могут прийти к выводу, что обновления могут выполняться с помощью POST. Не существует жесткого правила, какое использовать для обновлений или какое использовать для создания. Опять же, это соглашения, и я интуитивно склоняюсь к вышеупомянутым рассуждениям и следую им.

45
bharatj

POST - это как отправка письма в почтовый ящик или отправка письма в очередь электронной почты. PUT похож на то, когда вы кладете объект в яму или место на полке (у него есть известный адрес).

С POST, вы отправляете на адрес очереди или коллекции. С PUT вы кладете по адресу ПУНКТ.

PUT идемпотентен. Вы можете отправить запрос 100 раз, и это не будет иметь значения. POST не идемпотент. Если вы отправите запрос 100 раз, в вашем почтовом ящике вы получите 100 писем или 100 писем.

Общее правило: если вы знаете идентификатор или название предмета, используйте PUT. Если вы хотите, чтобы идентификатор или имя элемента были назначены принимающей стороной, используйте POST.

POST versus PUT

42
Homer6

Новый ответ (теперь, когда я лучше понимаю REST):

PUT - это просто заявление о том, какой контент сервис должен использовать для представления представлений ресурса, идентифицированного клиентом; POST - это указание того, какой контент служба должна содержать (возможно, дублировать), но сервер должен определить, как этот контент.

PUT x (если x идентифицирует ресурс ): "Заменить содержимое ресурса, идентифицированного x, моим содержимым".

PUT x (если x не идентифицирует ресурс): "Создайте новый ресурс, содержащий мое содержимое, и используйте x для его идентификации".

POST x: "Храните мое содержимое и дайте мне идентификатор, который я могу использовать для идентификации ресурса (старого или нового), содержащего указанное содержимое (возможно, смешанного с другим содержимым). Указанный ресурс должен быть идентичным или подчиняться тому, который идентифицирует x". "Ресурс y подчинен ресурсу x ", как правило, но не обязательно реализуется с помощью make y подпуть из 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, когда закончишь".

38
Jordan

Короткий ответ:

Простое правило: используйте POST для создания, используйте PUT для обновления.

Длинный ответ:

СООБЩЕНИЕ:

  • POST используется для отправки данных на сервер.
  • Полезно, когда URL ресурса неизвестен

ПОЛОЖИЛ:

  • PUT используется для передачи состояния на сервер
  • Полезно, когда URL ресурса известен

более длинный ответ:

Чтобы понять это, нам нужно спросить, зачем требовался PUT, какие проблемы пытался решить PUT, чего не мог POST.

С точки зрения архитектуры REST, ничего не имеет значения. Мы могли бы жить и без PUT. Но с точки зрения разработчика клиента это значительно упростило его жизнь.

До PUT клиенты не могли напрямую знать URL-адрес, сгенерированный сервером, или все, что он сгенерировал, или обновлены ли данные для отправки на сервер или нет. PUT избавил разработчика от всех этих головных болей. PUT является идемпотентом, PUT обрабатывает условия гонки, а PUT позволяет клиенту выбирать URL.

37
ishandutta2007

Ruby на Rails 4.0 будет использовать метод PATCH вместо PUT для частичного обновления.

RFC 5789 говорит о PATCH (с 1995 года):

Новый метод необходим для улучшения взаимодействия и предотвращения ошибок. Метод PUT уже определен для перезаписи ресурса новым телом и не может использоваться повторно для частичных изменений. В противном случае прокси и кеши, и даже клиенты и серверы, могут запутаться из-за результата операции. POST уже используется, но без широкой интероперабельности (для одного не существует стандартного способа обнаружить поддержку формата патча). PATCH упоминался в более ранних спецификациях HTTP, но не был полностью определен.

" Edge Rails: PATCH - новый основной метод HTTP для обновлений " объясняет это.

35
germanlinux

Риск повторения того, что уже было сказано, кажется важным помнить, что PUT подразумевает, что клиент контролирует то, что URL в конечном итоге будет при создании ресурса. Таким образом, часть выбора между PUT и POST будет зависеть от того, насколько вы можете доверять клиенту в предоставлении правильной, нормализованной URL, которые соответствуют вашей схеме URL.

Если вы не можете полностью доверять клиенту, чтобы он поступал правильно, было бы более целесообразно использовать POST, чтобы создать новый элемент, а затем отправить ответный URL-адрес клиенту в ответе.

27
skillet-thief

Я очень просто беру пример с графика времени в Facebook.

Случай 1: Когда вы публикуете что-то на своей временной шкале, это новая новая запись. Поэтому в этом случае они используют метод POST, потому что метод POST неидемпотентен.

Случай 2: Если ваш друг прокомментирует ваш пост в первый раз, это также создаст новую запись в базе данных, поэтому используется метод POST.

Случай 3: если ваш друг редактирует свой комментарий, в этом случае у него есть идентификатор комментария, поэтому он обновит существующий комментарий вместо создания новой записи в базе данных. Поэтому для этого типа операции используйте метод PUT, потому что он идемпотентен. *

В одной строке используйте POST чтобы добавить новую запись в базу данных и ПОЛОЖИТЬ в обновить = что-то в базе данных.

21
UniCoder

Наиболее важным фактором является надежность. Если сообщение POST теряется, состояние системы не определено. Автоматическое восстановление невозможно. Для сообщений PUT состояние не определено только до первой успешной попытки.

Например, может быть плохой идеей создавать транзакции по кредитным картам с помощью POST.

Если у вас есть автоматически сгенерированные URI на вашем ресурсе, вы все равно можете использовать PUT, передав сгенерированный URI (указывая на пустой ресурс) клиенту.

Некоторые другие соображения:

  • POST делает недействительными кэшированные копии всего содержащего ресурса (лучшая согласованность)
  • Ответы PUT не могут быть кэшированы, в то время как ответы POST (требуют Content-Location и expiration)
  • PUT менее поддерживается, например, Java ME, старые браузеры, брандмауэры
20
Hans Malherbe

Читатели, плохо знакомые с этой темой, будут поражены бесконечным обсуждением того, что вы должны делать, и относительным отсутствием уроков из опыта. Тот факт, что REST "предпочтительнее", чем SOAP, я полагаю, является результатом обучения на высоком уровне из опыта, но разве мы добились прогресса оттуда? Это 2016 год. Диссертация Роя была в 2000 году. Что мы разработали? Это было весело? Было ли легко интегрироваться? Поддерживать? Будет ли он справляться с ростом смартфонов и нестабильной мобильной связи?

По словам ME, реальные сети ненадежны. Запрашивает тайм-аут. Соединения сбрасываются. Сети отключаются на несколько часов или дней. Поезда идут в туннели с мобильными пользователями на борту. Для любого данного запроса (как иногда признается во всем этом обсуждении) запрос может упасть в воду на своем пути, или ответ может упасть в воде на обратном пути. В этих условиях выдача запросов PUT, POST и ​​DELETE непосредственно на основные ресурсы всегда казалась мне немного жестокой и наивной.

HTTP ничего не делает для обеспечения надежного завершения запроса-ответа, и это прекрасно, потому что это правильная работа сетевых приложений. Разрабатывая такое приложение, вы можете перепрыгивать через обручи, чтобы использовать PUT вместо POST, а затем больше обручей, чтобы выдать определенный тип ошибки на сервере, если вы обнаружите повторяющиеся запросы. Вернувшись к клиенту, вам придется перепрыгивать через обручи для интерпретации этих ошибок, повторного выбора, повторной проверки и повторной отправки.

Или вы можете сделать это: рассматривайте ваши небезопасные запросы как эфемерные однопользовательские ресурсы (назовем их действиями). Клиенты запрашивают новое "действие" на основном ресурсе с пустым POST к ресурсу. POST будет использоваться только для этого. После того, как клиент безопасно получит URI только что созданного действия, клиент помещает небезопасный запрос в URI действия , а не в целевой ресурс . Разрешить действие и обновить "реальный" ресурс - это правильно работа вашего API, и здесь он отделен от ненадежной сети.

Сервер работает, возвращает ответ и сохраняет его в соответствии с согласованным URI действия . Если что-то идет не так, клиент повторяет запрос (естественное поведение!), А если сервер его уже видел, он повторяет сохраненный ответ и больше ничего не делает .

Вы быстро заметите сходство с обещаниями: мы создаем и возвращаем заполнитель для результата, прежде чем что-либо делать. Также как и обещание, действие может быть успешным или неудачным один раз, но его результат может быть получен повторно.

Лучше всего то, что мы даем отправляющим и получающим приложениям возможность связать уникально идентифицированное действие с уникальностью в их соответствующих средах. И мы можем начать требовать и обеспечивать !, ответственное поведение клиентов: повторять ваши запросы сколько угодно, но не начинайте генерировать новое действие, пока не получите окончательный результат от уже существующего.

Таким образом, многочисленные острые проблемы уходят. Повторные запросы на вставку не будут создавать дубликаты, и мы не создадим реальный ресурс, пока не получим данные. (столбцы базы данных могут оставаться не обнуляемыми). Повторные запросы на обновление не будут попадать в несовместимые состояния и не будут перезаписывать последующие изменения. Клиенты могут (повторно) извлекать и без проблем обрабатывать исходное подтверждение по любой причине (сбой клиента, отсутствие ответа и т.д.).

Последовательные запросы на удаление могут видеть и обрабатывать исходное подтверждение, не вызывая ошибку 404. Если все происходит дольше, чем ожидалось, мы можем ответить временно, и у нас есть место, где клиент может проверить окончательный результат. Самая приятная часть этого паттерна - это его свойство кунг-фу (панда). Мы берем слабость, склонность клиентов повторять запрос всякий раз, когда они не понимают ответ, и превращаем его в силу :-)

Прежде чем сказать мне, что это не RESTful, рассмотрите многочисленные способы соблюдения принципов REST. Клиенты не создают URL-адреса. API остается доступным для обнаружения, хотя и с небольшим изменением семантики. HTTP-глаголы используются надлежащим образом. Если вы думаете, что это огромное изменение для реализации, я могу сказать вам по опыту, что это не так.

Если вы думаете, что у вас будет огромное количество данных для хранения, давайте поговорим об объемах: типичное подтверждение обновления составляет доли килобайта. HTTP в настоящее время дает вам одну или две минуты, чтобы ответить окончательно. Даже если вы храните действия только в течение недели, клиенты имеют достаточно шансов наверстать упущенное. Если у вас очень большие объемы, вам может потребоваться выделенное хранилище значений ключей, совместимое с кислотой, или решение в памяти.

14
bbsimonbb

Кажется, всегда есть некоторая путаница относительно того, когда использовать 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-методами GET и DELETE соответственно. Однако путаница заключается в операциях C(reate) и ​​U(update). В некоторых случаях можно использовать PUT для создания, тогда как в других случаях потребуется POST. Неоднозначность заключается в определении метода HTTP PUT по сравнению с методом HTTP POST.

Согласно спецификации HTTP 1.1 методы GET, HEAD, DELETE и PUT должны быть идемпотентными, а метод POST не идемпотентными. То есть операция является идемпотентной, если она может быть выполнена на ресурсе один или несколько раз и всегда возвращает одно и то же состояние этого ресурса. Принимая во внимание, что неидемпотентная операция может возвращать измененное состояние ресурса из одного запроса в другой. Следовательно, в неидемпотентной операции нет гарантии, что человек получит такое же состояние ресурса.

Исходя из приведенного выше определения идемпотента, я использую метод 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).

В обоих случаях эти операции могут выполняться несколько раз с одинаковыми результатами. То есть ресурс не будет изменен путем запроса операции более одного раза. Следовательно, истинная идемпотентная операция. Используйте метод 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 должно основываться на идемпотентном аспекте этой операции. То есть, если операция идемпотентна, используйте метод HTTP PUT. Если операция не идемпотентна, используйте метод HTTP POST.

14
Burhan

сервер-источник может создать ресурс с этим URI

Таким образом, вы используете POST и, возможно, но не обязательно PUT для создания ресурса. Вам не нужно поддерживать оба. Для меня POST вполне достаточно. Так что это дизайнерское решение.

Как упоминалось в вашей цитате, вы используете PUT для создания ресурса, которому IRI не назначен, и вы все равно хотите создать ресурс. Например, PUT /users/123/password обычно заменяет старый пароль новым, но вы можете использовать его для создания пароля, если он еще не существует (например, недавно зарегистрированными пользователями или восстановлением заблокированных пользователей).

13
inf3rno

Я собираюсь приземлиться со следующим:

PUT относится к ресурсу, идентифицированному URI. В этом случае вы обновляете его. Это часть трех глаголов, относящихся к ресурсам - удали и получи два других.

POST - это в основном сообщение в свободной форме, его значение определяется как "out of band". Если сообщение можно интерпретировать как добавление ресурса в каталог, это будет нормально, но в основном вам нужно понимать сообщение, которое вы отправляете (публикуете), чтобы знать, что произойдет с ресурсом.


Поскольку PUT, GET и DELETE относятся к ресурсу, они также по определению идемпотентны.

POST может выполнять другие три функции, но тогда семантика запроса будет потеряна на посредниках, таких как кэши и прокси. Это также относится к обеспечению безопасности ресурса, поскольку URI сообщения не обязательно указывает на ресурс, к которому он применяется (хотя может).

PUT не должен быть творением; служба может выдать ошибку, если ресурс еще не создан, но в противном случае обновите его. Или наоборот - он может создавать ресурс, но не разрешать обновления. Единственное, что требуется от PUT - это то, что он указывает на конкретный ресурс, а его полезная нагрузка - это представление этого ресурса. Успешный PUT означает (исключая помехи), что GET будет получать тот же ресурс.


Правка: еще одна вещь - PUT может создавать, но если это так, то идентификатор должен быть естественным ID - AKA адрес электронной почты. Таким образом, когда вы PUT дважды, второй пут - это обновление первого. Это делает его идемпотентным.

Если сгенерирован идентификатор (например, новый идентификатор сотрудника), то второй PUT с тем же URL-адресом создаст новую запись, которая нарушает идемпотентное правило. В этом случае глаголом будет POST, а сообщение (не ресурс) будет означать создание ресурса с использованием значений, определенных в этом сообщении.

11
Gerard ONeill

В дополнение к различиям, предложенным другими, я хочу добавить еще один.

В методе POST вы можете отправлять параметры тела в 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 метод

11
Rohit Dhiman

Предполагается, что семантика различна, в том смысле, что "PUT", как и "GET", считается идемпотентным - это означает, что один и тот же точный запрос PUT можно выполнить несколько раз, и в результате вы получите такой же результат, как если бы вы выполнили его только один раз.

Я опишу соглашения, которые, на мой взгляд, наиболее широко используются и наиболее полезны:

Когда вы помещаете ресурс по определенному URL-адресу, происходит следующее: он должен сохраняться по этому URL-адресу или что-то в этом роде.

Когда вы POST обращаетесь к ресурсу по определенному URL-адресу, вы часто публикуете связанную информацию на этот URL-адрес. Это означает, что ресурс по URL уже существует.

Например, когда вы хотите создать новый поток, вы можете положить его на какой-нибудь URL. Но когда вы хотите POST сообщение для существующего потока, вы POST на его URL.

Что касается изменения свойств потока, вы можете сделать это с помощью PUT или POST. В основном, используйте "PUT" только тогда, когда операция идемпотентна, в противном случае используйте POST.

Однако обратите внимание, что не все современные браузеры поддерживают HTTP-глаголы, кроме GET или POST.

9
Gregory Magarshak

Большую часть времени вы будете использовать их так:

  • ОПУБЛИКОВАТЬ ресурс в коллекцию
  • ПОЛОЖИТЬ ресурс, идентифицируемый коллекцией /: id

Например:

  • СООБЩЕНИЕ/items
  • ПОЛОЖИТЬ/items/1234

В обоих случаях тело запроса содержит данные для ресурса, который будет создан или обновлен. Из названий маршрутов должно быть очевидно, что POST не идемпотентен (если вы вызываете его 3 раза, это создаст 3 объекта), но PUT является идемпотентом (если вы вызываете его 3 раза, результат одинаков) , PUT часто используется для операции "upsert" (создание или обновление), но вы всегда можете вернуть ошибку 404, если хотите использовать ее только для изменения.

Обратите внимание, что POST "создает" новый элемент в коллекции, а PUT "заменяет" элемент по заданному URL-адресу, но это очень распространенная практика - использовать PUT для частичных модификаций, то есть использовать его только для обновления существующих ресурсов и изменения только включенных полей в теле (игнорируя другие поля). Это технически неверно, если вы хотите быть REST-пуристом, PUT должен заменить весь ресурс, и вы должны использовать PATCH для частичного обновления. Лично меня не волнует, насколько поведение ясное и согласованное на всех ваших конечных точках API.

Помните, REST - это набор соглашений и рекомендаций, упрощающих работу вашего API. Если у вас сложный обходной путь только для того, чтобы установить флажок "RESTfull", значит, вы побеждаете цель;)

7
tothemario

Хотя, возможно, существует агностический способ их описания, он, похоже, вступает в противоречие с различными утверждениями из ответов на веб-сайты.

Давайте будем очень ясными и прямыми. Если вы - разработчик .NET, работающий с Web API, факты (из документации Microsoft API) http://www.asp.net/web-api/overview/creating-web-apis/creating -a-веб-апи-что-опора-падла-операция :

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

Конечно, вы "можете" использовать "POST" для обновления, но просто следуйте соглашениям, изложенным для вас с вашей данной платформой. В моем случае это .NET/Web API, поэтому PUT для ОБНОВЛЕНИЯ не обсуждается.

Я надеюсь, что это поможет любым разработчикам Microsoft, которые читают все комментарии со ссылками на сайты Amazon и Sun/Java.

7
Tom Stickel

Вот простое правило:

ПОЛОЖИТЬ URL-адрес должен использоваться для обновления или создания ресурса, который может быть расположен по этому URL-адресу.

POST для URL-адреса следует использовать для обновления или создания ресурса, который расположен по какому-либо другому ("подчиненному") URL-адресу или не может быть обнаружен через HTTP.

6
Adam Griffiths

Если вы знакомы с операциями с базами данных, есть

  1. Выбрать
  2. Вставить
  3. Обновление
  4. Удалять
  5. Объединить (обновить, если уже существует, еще вставить)

Я использую PUT для слияния и обновления как операции и использую POST для вставок.

6
Rajan

На практике POST хорошо работает для создания ресурсов. URL вновь созданного ресурса должен быть возвращен в заголовке ответа Location. PUT следует использовать для полного обновления ресурса. Пожалуйста, поймите, что это лучшие практики при разработке RESTful API. Спецификация HTTP как таковая не ограничивает использование PUT/POST с некоторыми ограничениями для создания/обновления ресурсов. Взгляните на http://techoctave.com/c7/posts/71-Twitter-rest-api-dissected , в котором обобщены лучшие практики.

5
java_geek

POST: Используйте его для создания новых ресурсов. Это как INSERT (оператор SQL) с автоматически увеличивающимся идентификатором. В части ответа он содержит новый сгенерированный идентификатор.

POST также используется для обновления записи.

PUT: Используйте его для создания нового ресурса, но здесь я знаю ключ идентификации. Это как INSERT (оператор SQL), где я заранее знаю ключ идентификации. В ответной части ничего не отправляется.

PUT также используется для обновления ресурса

3
sushil pandey

Итак, какой из них следует использовать для создания ресурса? Или нужно поддерживать оба?

Вы должны использовать PATCH. Вы УДАЛИТЕ список вопросов, таких как

PATCH /questions HTTP/1.1

со списком, содержащим ваш создаваемый объект, как

[
    {
        "title": "I said semantics!",
        "content": "Is this serious?",
        "answer": "Not really"
    }
]

Это запрос на исправление как

  • вы изменяете существующий список ресурсов не предоставляя полностью новый контент
  • вы изменяете состояние вашего нового вопроса с несуществующего на существующее без предоставления всех данных (сервер, скорее всего, добавит id).

Большим преимуществом этого метода является то, что вы можете создавать несколько объектов, используя один запрос, просто предоставив их все в списке.

Это то, что PUT явно не может. Вы можете использовать POST для создания нескольких сущностей, так как это кухонный приемник HTTP и может делать практически все.

Недостатком является то, что, вероятно, никто не использует PATCH таким образом. Боюсь, я только что это придумал, но, надеюсь, предоставил хорошую аргументацию.

Вместо этого вы можете использовать CREATE, поскольку допускаются пользовательские HTTP-глаголы, просто они могут не работать с некоторыми инструментами.

Что касается семантики, CREATE ИМХО является единственным правильным выбором, все остальное - это квадратный колышек в круглой дыре. К сожалению, все, что у нас есть, это круглые отверстия.

2
maaartinus