ПОСТ против ПОЧТЫ в ОТДЫХЕ - PullRequest
4976 голосов
/ 10 марта 2009

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

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

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

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

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

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

Ответы [ 32 ]

3927 голосов
/ 10 марта 2009

Всего:

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

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

Великолепно можно использовать и то, и другое, поэтому какой из них мне следует использовать в моем проекте RESTful: Вам не нужно поддерживать PUT и POST.

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

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

  • Вы называете свои объекты URL, которые вы создаете явно, или позволяете серверу решать? Если вы называете их, используйте PUT. Если вы позволите серверу решить, используйте POST.
  • PUT является идемпотентом, поэтому, если вы поместите объект дважды, это не даст никакого эффекта. Это хорошее свойство, поэтому я бы использовал 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/
2070 голосов
/ 22 апреля 2010

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

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


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

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

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


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

так:

POST /expense-report

или

PUT  /expense-report/10929
650 голосов
/ 07 апреля 2010
  • POST на URL создает дочерний ресурс на сервере, определенном URL.
  • PUT на 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 являются идемпотентными .

RFC звучит так:

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

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

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

С техникой «ОТДЫХ без PUT» идея заключается в том, что потребители вынуждает публиковать новые «неназванные» ресурсы запроса. Как обсуждалось ранее, изменение почтового адреса клиента является POST на новый Ресурс «ChangeOfAddress», а не PUT ресурса «Клиент» с значение поля другого почтового адреса.

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

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

191 голосов
/ 15 августа 2013

Резюме:

Создать:

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

PUT

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

PUT /resources/<newResourceId> HTTP/1.1 

POST

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

POST /resources HTTP/1.1

Обновление:

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

PUT

Обновляет ресурс, используя Существующий идентификатор ресурса в качестве идентификатора в URI / resources или collection .

PUT /resources/<existingResourceId> HTTP/1.1

Пояснение:

При работе с REST и URI в целом у вас есть универсальный для левый и специфический для правый . Обобщения обычно называются коллекциями , а более специфичные элементы можно назвать resource . Обратите внимание, что ресурс может содержать коллекцию .

Примеры:

<- универсальный - специфичный ->

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

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

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

PUT /users/john HTTP/1.1

вы сообщаете серверу об обновлении или создаете, если оно не существует, ресурс john в users collection .

Spec:

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

POST

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

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

PUT

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

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

Справка:

170 голосов
/ 15 января 2011

Я бы хотел добавить свой «прагматичный» совет. Используйте 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
163 голосов
/ 23 октября 2011

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

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

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

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

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

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

121 голосов
/ 10 марта 2009

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

PUT    /items/1      #=> update
POST   /items        #=> create
96 голосов
/ 11 сентября 2015

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

Enter image description here

Аналогия:

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

enter image description here

Социальные медиа / сетевые аналогии:

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

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 коллекции.

59 голосов
/ 30 октября 2013

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

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

REST API не должен определять фиксированные имена ресурсов или иерархии ( очевидная связь клиента и сервера). Серверы должны иметь свободу контролировать свое собственное пространство имен. Вместо этого позвольте серверам инструктировать клиенты о том, как создать соответствующие 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. Клиент отправляет новый ресурс на сервер.
  2. Сервер обрабатывает запрос и отправляет ответ.
  3. Клиент никогда не получает ответ.
  4. Сервер не знает, что клиент не получил ответ.
  5. У клиента нет URL для ресурса (поэтому PUT не является опцией) и повторяется POST.
  6. POST не идемпотент и сервер…

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

10.4.10 409 Конфликт

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

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

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

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

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

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

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

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

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

Подробнее об этом читайте в статье .

...