ПОСТ против ПОЧТЫ в ОТДЫХЕ
Согласно спецификации HTTP/1.1:
POST
Этот метод используется для запроса, чтобы исходный сервер принял объект, включенный в запрос, в качестве нового подчиненного ресурса, идентифицируемогоRequest-URI
вRequest-Line
Другими словами, POST
используется для создания.
PUT
Метод запрашивает, чтобы вложенная сущность была сохранена под предоставленнымRequest-URI
, ЕслиRequest-URI
ссылается на уже существующий ресурс, заключенный объект ДОЛЖЕН рассматриваться как модифицированная версия того, который находится на исходном сервере. ЕслиRequest-URI
не указывает на существующий ресурс, и тот URI может быть определен как новый ресурс запрашивающим пользовательским агентом, сервер происхождения может создать ресурс с этим URI."
То есть, PUT
используется для создания или обновления.
Итак, какой из них следует использовать для создания ресурса? Или нужно поддерживать оба?
46 ответов
В общем и целом:
Оба PUT и POST могут быть использованы для создания.
Вы должны спросить: "Для чего вы выполняете действие?" чтобы отличить то, что вы должны использовать. Предположим, вы разрабатываете API для вопросов. Если вы хотите использовать POST, вы должны сделать это со списком вопросов. Если вы хотите использовать PUT, вы должны сделать это для конкретного вопроса.
Можно использовать оба варианта, так что какой из них мне следует использовать в моем дизайне RESTful:
Вам не нужно поддерживать PUT и POST.
Что используется, остается за вами. Но просто не забудьте использовать правильный в зависимости от того, на какой объект вы ссылаетесь в запросе.
Некоторые соображения:
- Вы называете свои объекты URL, которые вы создаете явно, или позволяете серверу решать? Если вы называете их, используйте PUT. Если вы позволите серверу решить, используйте POST.
- PUT идемпотентен, поэтому, если вы поместите объект дважды, это не даст никакого эффекта. Это хорошее свойство, поэтому я бы использовал 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-адресу новых объектов будет возвращен вам.
ПОЛОЖИЛ:
Используется для создания ресурса или его перезаписи. Пока вы указываете ресурсам новый URL.
Для нового ресурса:
PUT /questions/<new_question> HTTP/1.1 Host: www.example.com/
Чтобы перезаписать существующий ресурс:
PUT /questions/<existing_question> HTTP/1.1 Host: www.example.com/
Вы можете найти утверждения в Интернете, которые говорят
- POST должен использоваться, чтобы создать ресурс, и PUT должен использоваться, чтобы изменить один
- PUT следует использовать для создания ресурса, а POST - для его изменения.
Ни один не совсем прав.
Лучше выбирать между PUT и POST, основываясь на идемпотентности действия.
PUT подразумевает размещение ресурса - полная замена всего, что доступно по данному URL, другой вещью. По определению, PUT является идемпотентом. Делайте это столько раз, сколько хотите, и результат тот же. x=5
идемпотент. Вы можете положить ресурс независимо от того, существует ли он ранее или нет (например, создать или обновить)!
POST обновляет ресурс, добавляет вспомогательный ресурс или вызывает изменение. POST не идемпотент, в том смысле, что x++
не идемпотент.
По этому аргументу PUT предназначен для создания, когда вы знаете URL-адрес того, что вы создадите. POST может использоваться для создания, когда вы знаете URL "фабрики" или менеджера для категории вещей, которые вы хотите создать.
так:
POST /expense-report
или же:
PUT /expense-report/10929
- POST для URL-адреса создает дочерний ресурс по URL-адресу, определенному сервером.
- PUT to URL создает / заменяет ресурс полностью в URL-адресе, определенном клиентом.
- PATCH to 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. Смотрите "ОТДЫХ без ПУТА"
С техникой "REST без PUT" идея заключается в том, что потребители вынуждены публиковать новые "несущественные" ресурсы запросов. Как обсуждалось ранее, изменение почтового адреса клиента - это POST на новый ресурс "ChangeOfAddress", а не PUT ресурса "Customer" с другим значением поля почтового адреса.
взято из REST API Design - Моделирование ресурсов Пракашем Субраманиамом из Thoughtworks
Это вынуждает API избегать проблем с переходом состояний при обновлении одного ресурса несколькими клиентами и более точно согласуется с источником событий и CQRS. Когда работа выполняется асинхронно, установка POST и ожидание ее применения представляется целесообразной.
POST означает "создать новый", как в "Вот вход для создания пользователя, создайте его для меня".
PUT означает "вставить, заменить, если уже существует", как в "Вот данные для пользователя 5".
Вы отправляете на example.com/users, поскольку вы еще не знаете URL пользователя, вы хотите, чтобы сервер его создал.
Вы кладете на example.com/users/id, поскольку хотите заменить / создать конкретного пользователя.
Двойная публикация с одинаковыми данными означает создание двух идентичных пользователей с разными идентификаторами. PUT дважды с одними и теми же данными создает пользователя первым и обновляет его до того же состояния во второй раз (без изменений). Поскольку после PUT вы получаете одно и то же состояние, независимо от того, сколько раз вы его выполняете, оно называется "одинаково мощным" каждый раз - идемпотентным. Это полезно для автоматической повторной отправки запросов. Нет больше "вы уверены, что хотите отправить", когда вы нажимаете кнопку "Назад" в браузере.
Общий совет - использовать POST, когда вам нужно, чтобы сервер контролировал генерацию URL ваших ресурсов. В противном случае используйте PUT. Предпочитаю PUT, а не POST.
Резюме:
Создайте:
Можно выполнить как PUT, так и POST следующим образом:
ПОЛОЖИЛ
Создает новый ресурс с newResourceId в качестве идентификатора под URI / resources или коллекцией.
PUT /resources/<newResourceId> HTTP/1.1
СООБЩЕНИЕ
Создает новый ресурс в URI / resources или коллекции. Обычно идентификатор возвращается сервером.
POST /resources HTTP/1.1
Обновить:
Может выполняться только с помощью PUT следующим образом:
ПОЛОЖИЛ
Обновляет ресурс с существующим ResourceId в качестве идентификатора в 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
Вы публикуете нового пользователя в коллекции пользователей.
Если вы продолжите и попробуете что-то вроде этого:
POST /users/john HTTP/1.1
это будет работать, но семантически вы говорите, что хотите добавить ресурс в коллекцию john в коллекции users.
Как только вы используете PUT, вы ссылаетесь на ресурс или отдельный элемент, возможно, внутри коллекции. Поэтому, когда вы говорите:
PUT /users/john HTTP/1.1
вы сообщаете серверу об обновлении или создаете, если он не существует, ресурс john в коллекции пользователей.
Spec:
Позвольте мне выделить некоторые важные части спецификации:
СООБЩЕНИЕ
Метод POST используется для запроса, чтобы исходный сервер принял объект, включенный в запрос, в качестве нового подчиненного ресурса, идентифицируемого Request-URI в строке запроса
Следовательно, создает новый ресурс в коллекции.
ПОЛОЖИЛ
Метод PUT запрашивает, чтобы вложенный объект был сохранен под предоставленным Request-URI. Если Request-URI ссылается на уже существующий ресурс, вложенный объект СЛЕДУЕТ рассматривать как модифицированную версию, находящуюся на исходном сервере. Если Request-URI не указывает на существующий ресурс и этот URI может быть определен как новый ресурс запрашивающим пользовательским агентом, сервер происхождения может создать ресурс с этим URI."
Следовательно, создавать или обновлять на основе существования ресурса.
Ссылка:
Я хотел бы добавить мой "прагматичный" совет. Используйте 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
Оба используются для передачи данных между клиентом и сервером, но между ними есть тонкие различия:
Аналогия:
- PUT т.е. возьми и положи, где это было.
- POST как отправить почту в почтовом отделении.
Используйте POST для создания и PUT для обновления. Вот как это делает Ruby on Rails.
PUT /items/1 #=> update
POST /items #=> create
REST - это концепция очень высокого уровня. На самом деле, он даже не упоминает HTTP вообще!
Если у вас есть какие-либо сомнения относительно того, как реализовать REST в HTTP, вы всегда можете взглянуть на спецификацию протокола публикации Atom (Atom Pub). Atom Pub - это стандарт для написания веб-сервисов RESTful с HTTP, который был разработан многими светилами HTTP и REST при участии Роя Филдинга, изобретателя REST и (со) изобретателя самого HTTP.
На самом деле, вы даже можете использовать Atom Pub напрямую. Хотя он и вышел из сообщества блогеров, он никоим образом не ограничен блогами: это общий протокол для RESTful взаимодействия с произвольными (вложенными) коллекциями произвольных ресурсов через HTTP. Если вы можете представить свое приложение как вложенную коллекцию ресурсов, то вы можете просто использовать Atom Pub и не беспокоиться о том, использовать ли PUT или POST, какие коды состояния HTTP возвращать и все эти подробности.
Вот что Atom Pub говорит о создании ресурса (раздел 9.2):
Чтобы добавить участников в коллекцию, клиенты отправляют запросы POST на URI коллекции.
Решение о том, использовать ли PUT или POST для создания ресурса на сервере с HTTP + REST API, зависит от того, кому принадлежит структура URL. Знание или участие клиента в определении структуры URL является ненужной связью, сродни нежелательным связям, возникающим из SOA. Экранирование типов муфт является причиной популярности REST. Поэтому правильным методом для использования является POST. Есть исключения из этого правила, и они возникают, когда клиент желает сохранить контроль над структурой расположения ресурсов, которые он развертывает. Это редко и, вероятно, означает, что что-то еще не так.
На этом этапе некоторые люди утверждают, что если используются RESTful-URL, клиент знает URL-адрес ресурса, и поэтому PUT является приемлемым. В конце концов, именно поэтому важны канонические, нормализованные URL-адреса Ruby on Rails, Django, посмотрите на 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), но они все равно делают это, потому что не знают, как решить эту проблему. Эта проблема проявляется в следующей ситуации:
- Клиент POST новый ресурс на сервер.
- Сервер обрабатывает запрос и отправляет ответ.
- Клиент никогда не получает ответ.
- Сервер не знает, что клиент не получил ответ.
- У клиента нет URL-адреса для ресурса (поэтому PUT не является опцией) и повторяется POST.
- ПОСТ не идемпотент, а сервер…
На шестом этапе люди обычно не понимают, что делать. Тем не менее, нет никаких причин для создания этой проблемы. Вместо этого можно использовать HTTP, как указано в RFC 2616, и сервер отвечает:
10.4.10 409 Конфликт
Запрос не может быть выполнен из-за конфликта с текущим состоянием ресурса. Этот код разрешен только в ситуациях, когда ожидается, что пользователь сможет разрешить конфликт и повторно отправить запрос. Тело ответа ДОЛЖНО включать достаточно
информация для пользователя, чтобы распознать источник конфликта. В идеале, объект ответа должен включать в себя достаточно информации, чтобы пользователь или пользовательский агент мог решить проблему; Однако это может быть невозможно и не требуется.
Конфликты чаще всего возникают в ответ на запрос PUT. Например, если использовалось управление версиями, а объект PUT включал изменения в ресурс, которые конфликтуют с ресурсами, сделанными ранее (сторонним) запросом, сервер может использовать ответ 409, чтобы указать, что он не может выполнить запрос, В этом случае объект ответа, скорее всего, будет содержать список различий между двумя версиями в формате, определяемом типом содержимого ответа.
Ответ с кодом состояния 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 должен использоваться для создания.
Для получения дополнительной информации об этом, прочитайте эту статью.
Мне нравится этот совет из определения PUT в RFC 2616:
Принципиальное различие между запросами POST и PUT отражается в различном значении Request-URI. URI в запросе POST идентифицирует ресурс, который будет обрабатывать вложенную сущность. Этот ресурс может быть процессом приема данных, шлюзом к другому протоколу или отдельным объектом, который принимает аннотации. Напротив, URI в запросе PUT идентифицирует объект, заключенный в запросе - пользовательский агент знает, для чего предназначен URI, и сервер НЕ ДОЛЖЕН пытаться применить запрос к какому-либо другому ресурсу.
Это согласуется с другим советом, заключающимся в том, что PUT лучше всего применять к ресурсам, которые уже имеют имя, а POST хорош для создания нового объекта под существующим ресурсом (и позволяет серверу присвоить ему имя).
Я интерпретирую это и требования идемпотентности к PUT, чтобы означать, что:
- POST хорош для создания новых объектов в коллекции (и для создания не нужно быть идемпотентом)
- PUT хорош для обновления существующих объектов (и обновление должно быть идемпотентным)
- POST может также использоваться для неидемпотентных обновлений существующих объектов (особенно, для изменения части объекта без указания всей цели - если вы об этом думаете, создание нового члена коллекции на самом деле является частным случаем такого рода обновление, с точки зрения коллекции)
- PUT также может использоваться для создания, если и только если вы разрешите клиенту называть ресурс. Но поскольку REST-клиенты не должны делать предположения о структуре URL, это не так, как задумано.
Короче:
PUT является идемпотентным, где состояние ресурса будет одинаковым, если одна и та же операция выполняется один или несколько раз.
POST не идемпотентен, где состояние ресурса может стать другим, если операция выполняется несколько раз по сравнению с выполнением одного раза.
Аналогия с запросом к базе данных
PUT Можно подумать, что-то похожее на "ОБНОВЛЕНИЕ СТУДЕНТА SET address = "abc", где id =" 123 ";
POST Вы можете придумать что-то вроде "INSERT INTO STUDENT(имя, адрес) VALUES ("abc", "xyzzz");
Идентификатор студента генерируется автоматически.
С PUT, если один и тот же запрос выполняется несколько раз или один раз, состояние таблицы STUDENT остается неизменным.
В случае POST, если один и тот же запрос выполняется несколько раз, в базе данных создается несколько записей Student, и состояние базы данных изменяется при каждом выполнении запроса INSERT.
ПРИМЕЧАНИЕ. PUT требуется местоположение ресурса (уже ресурс), для которого должно происходить обновление, тогда как POST этого не требует. Следовательно, POST интуитивно предназначен для создания нового ресурса, а PUT необходим для обновления уже существующего ресурса.
Некоторые могут придумать, что обновления могут выполняться с помощью POST. Не существует жесткого правила, какое использовать для обновлений или какое использовать для создания. Опять же, это условности, и я интуитивно склоняюсь к вышеупомянутым рассуждениям и следую им.
POST - это как отправка письма в почтовый ящик или отправка письма в очередь электронной почты. PUT похож на то, когда вы кладете объект в яму или место на полке (у него есть известный адрес).
С POST, вы отправляете на адрес очереди или коллекции. С PUT вы кладете по адресу ПУНКТ.
PUT идемпотентен. Вы можете отправить запрос 100 раз, и это не будет иметь значения. ПОСТ не идемпотент. Если вы отправите запрос 100 раз, в вашем почтовом ящике вы получите 100 писем или 100 писем.
Общее правило: если вы знаете идентификатор или название предмета, используйте PUT. Если вы хотите, чтобы идентификатор или имя элемента были назначены принимающей стороной, используйте POST.
Короткий ответ:
Простое правило: используйте POST для создания, PUT для обновления.
Длинный ответ:
СООБЩЕНИЕ:
- POST используется для отправки данных на сервер.
- Полезно, когда URL ресурса неизвестен
ПОЛОЖИЛ:
- PUT используется для передачи состояния на сервер
- Полезно, когда URL ресурса известен
Более длинный ответ:
Чтобы понять это, нам нужно спросить, зачем требовался PUT, какие проблемы пытался решить PUT, чего не мог POST.
С точки зрения архитектуры REST нет ничего, что имело бы значение. Мы могли бы жить и без PUT. Но с точки зрения разработчика клиента это значительно упростило его жизнь.
До PUT клиенты не могли напрямую знать URL-адрес, сгенерированный сервером, или все, что он сгенерировал, или обновлены ли данные для отправки на сервер или нет. PUT избавил разработчика от всех этих головных болей. PUT является идемпотентом, PUT обрабатывает условия гонки, а PUT позволяет клиенту выбирать URL.
Новый ответ (теперь, когда я лучше понимаю REST):
PUT - это просто заявление о том, какой контент сервис должен использовать для представления представлений ресурса, идентифицированных клиентом; POST - это заявление о том, какой контент должен содержать сервис (возможно, дублированный), но сервер должен определить, как этот контент.
PUT x
(если x
идентифицирует ресурс): "Заменить содержимое ресурса, идентифицируемого x
с моим содержанием. "
PUT x
(если x
не идентифицирует ресурс): "Создайте новый ресурс, содержащий мой контент и используйте x
идентифицировать это. "
POST x
: "Храните мой контент и дайте мне идентификатор, который я могу использовать для идентификации ресурса (старого или нового), содержащего указанный контент (возможно, смешанный с другим контентом). Указанный ресурс должен быть идентичным или подчиненным тому, который x
идентифицирует. "" ресурсy подчинен ресурсу x", как правило, но не обязательно реализуется путем превращения y в подпуть x (например, x = /foo
и у = /foo/bar
) и изменение представления (й) ресурса x для отражения существования нового ресурса, например, с гиперссылкой на ресурс y и некоторыми метаданными. Только последний действительно важен для хорошего дизайна, так как URL-адреса непрозрачны в REST - вы должны использовать гипермедиа вместо создания URL-адреса на стороне клиента, чтобы в любом случае пройти через сервис.
В REST нет такого понятия, как ресурс, содержащий "контент". Я называю "контентом" данные, которые служба использует для последовательной визуализации представлений. Обычно он состоит из нескольких связанных строк в базе данных или файле (например, в файле изображения). Служба должна преобразовывать контент пользователя во что-то, что может использовать служба, например, преобразовывать полезную нагрузку JSON в операторы SQL.
Оригинальный ответ (может быть легче читать):
PUT /something
(если /something
уже существует): "Возьми все, что у тебя есть на /something
и замени это тем, что я тебе даю ".
PUT /something
(если /something
не существует): "Возьми то, что я тебе даю, и положи на /something
".
POST /something
: "Возьми то, что я тебе даю, и положи куда угодно /something
пока вы дадите мне его URL, когда закончите. "
Ruby on Rails 4.0 будет использовать метод PATCH вместо PUT для частичного обновления.
RFC 5789 говорит о PATCH (с 1995 года):
Новый метод необходим для улучшения взаимодействия и предотвращения ошибок. Метод PUT уже определен для перезаписи ресурса новым телом и не может использоваться повторно для частичных изменений. В противном случае прокси и кеши, и даже клиенты и серверы, могут запутаться в результате выполнения операции. POST уже используется, но без широкой совместимости (во-первых, не существует стандартного способа обнаружения поддержки формата патча). PATCH упоминался в более ранних спецификациях HTTP, но не был полностью определен.
" Edge Rails: PATCH - новый основной метод HTTP для обновлений", объясняет это.
В дополнение к различиям, предложенным другими, я хочу добавить еще одну.
В методе 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
Имея риск повторения того, что уже было сказано, важно помнить, что PUT подразумевает, что клиент контролирует, каким будет URL-адрес, когда он будет создавать ресурс. Таким образом, часть выбора между PUT и POST будет зависеть от того, насколько вы можете доверять клиенту, предоставляя правильный, нормализованный URL, который согласуется с вашей схемой URL.
Если вы не можете полностью доверять клиенту, чтобы он поступал правильно, было бы более целесообразно использовать POST для создания нового элемента, а затем отправлять URL-адрес клиенту в ответе.
Я очень просто беру пример с графика времени в Facebook.
Случай 1: Когда вы публикуете что-то на своей временной шкале, это новая новая запись. Так что в этом случае они используют метод POST, потому что метод POST не идемпотентен.
Случай 2: Если ваш друг прокомментирует ваш пост в первый раз, это также создаст новую запись в базе данных, поэтому будет использоваться метод POST.
Случай 3: Если ваш друг редактирует свой комментарий, в этом случае у него есть идентификатор комментария, поэтому он обновит существующий комментарий вместо создания новой записи в базе данных. Поэтому для этого типа операции используйте метод PUT, потому что он идемпотентен. *
В одной строке используйте POST для добавления новой записи в базу данных и PUT для обновления чего-либо в базе данных.
Наиболее важным фактором является надежность. Если сообщение POST теряется, состояние системы не определено. Автоматическое восстановление невозможно. Для сообщений PUT состояние не определено только до первой успешной попытки.
Например, может быть плохой идеей создавать транзакции по кредитным картам с помощью POST.
Если у вас есть автоматически сгенерированные URI на вашем ресурсе, вы все равно можете использовать PUT, передав сгенерированный URI (указывая на пустой ресурс) клиенту.
Некоторые другие соображения:
- POST делает недействительными кэшированные копии всего содержащего ресурса (лучшая согласованность)
- Ответы PUT не кэшируются, в то время как ответы POST (требуют Content-Location и expiration)
- PUT менее поддерживается, например, Java ME, старыми браузерами, брандмауэрами
Читатели, плохо знакомые с этой темой, будут поражены бесконечным обсуждением того, что вы должны делать, и относительным отсутствием уроков из опыта. Тот факт, что REST является "более предпочтительным", чем SOAP, является, я полагаю, высокоуровневым обучением на основе опыта, но разве мы добились прогресса оттуда? Это 2016 год. Диссертация Роя была в 2000 году. Что мы разработали? Это было весело? Было ли легко интегрироваться? Поддерживать? Будет ли он справляться с ростом смартфонов и нестабильной мобильной связи?
По словам ME, реальные сети ненадежны. Запрашивает тайм-аут. Соединения сбрасываются. Сети отключаются на несколько часов или дней. Поезда идут в туннели с мобильными пользователями на борту. Для любого данного запроса (как иногда признается во всем этом обсуждении) запрос может упасть в воду на своем пути, или ответ может упасть в воде на обратном пути. В этих условиях выдача запросов PUT, POST и DELETE непосредственно на основные ресурсы всегда казалась мне немного жестокой и наивной.
HTTP ничего не делает для обеспечения надежного завершения запроса-ответа, и это прекрасно, потому что это правильная работа сетевых приложений. Разрабатывая такое приложение, вы можете перепрыгивать через обручи, чтобы использовать PUT вместо POST, а затем больше обручей, чтобы дать определенную ошибку на сервере, если вы обнаружите повторяющиеся запросы. Вернувшись к клиенту, вам придется перепрыгивать через обручи для интерпретации этих ошибок, повторного выбора, повторной проверки и повторной отправки.
Или вы можете сделать это: рассматривайте ваши небезопасные запросы как эфемерные однопользовательские ресурсы (назовем их действиями). Клиенты запрашивают новое "действие" на основном ресурсе с пустым POST к ресурсу. POST будет использоваться только для этого. Как только надежно завладеет URI только что созданного действия, клиент помещает небезопасный запрос в URI действия, а не в целевой ресурс. Разрешить действие и обновить "реальный" ресурс - это правильно работа вашего API, и здесь он отделен от ненадежной сети.
Сервер выполняет бизнес, возвращает ответ и сохраняет его в соответствии с согласованным URI действия. Если что-то идет не так, клиент повторяет запрос (естественное поведение!), А если сервер его уже видел, он повторяет сохраненный ответ и больше ничего не делает.
Вы быстро заметите сходство с обещаниями: мы создаем и возвращаем заполнитель для результата, прежде чем что-либо делать. Также как и обещание, действие может быть успешным или неудачным один раз, но его результат может быть получен повторно.
Лучше всего то, что мы даем отправляющим и принимающим приложениям возможность связать уникально идентифицированное действие с уникальностью в их соответствующих средах. И мы можем начать требовать и обеспечивать!, ответственное поведение клиентов: повторять ваши запросы сколько угодно, но не начинайте генерировать новое действие, пока не получите окончательный результат от уже существующего.
Таким образом, многочисленные острые проблемы уходят. Повторные запросы на вставку не будут создавать дубликаты, и мы не создадим реальный ресурс, пока не получим данные. (столбцы базы данных могут оставаться не обнуляемыми). Повторные запросы на обновление не будут попадать в несовместимые состояния и не будут перезаписывать последующие изменения. Клиенты могут (повторно) извлекать и без проблем обрабатывать исходное подтверждение по любой причине (сбой клиента, отсутствие ответа и т. Д.).
Последовательные запросы на удаление могут видеть и обрабатывать исходное подтверждение, не вызывая ошибку 404. Если все займет больше времени, чем ожидалось, мы можем дать предварительный ответ, и у нас есть место, где клиент может проверить окончательный результат. Самая приятная часть этого паттерна - это его свойство кунг-фу (панда). Мы берем слабость, склонность клиентов повторять запрос всякий раз, когда они не понимают ответ, и превращаем его в силу:-)
Прежде чем сказать мне, что это не RESTful, рассмотрите многочисленные способы соблюдения принципов REST. Клиенты не создают URL. API остается доступным для обнаружения, хотя и с небольшим изменением семантики. HTTP-глаголы используются надлежащим образом. Если вы думаете, что это огромное изменение для реализации, я могу вам сказать по опыту, что это не так.
Если вы думаете, что у вас будет огромное количество данных для хранения, давайте поговорим об объемах: типичное подтверждение обновления составляет доли килобайта. HTTP в настоящее время дает вам одну или две минуты, чтобы ответить окончательно. Даже если вы сохраняете действия только на неделю, у клиентов есть достаточно шансов наверстать упущенное. Если у вас очень большие объемы, вам может потребоваться выделенное хранилище значений ключей, совместимое с кислотой, или решение в памяти.
Кажется, всегда есть некоторая путаница относительно того, когда использовать 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.
исходный сервер может создать ресурс с этим URI
Таким образом, вы используете POST и, возможно, но не PUT для создания ресурса. Вам не нужно поддерживать оба. Для меня POST вполне достаточно. Так что это дизайнерское решение.
Как упоминалось в вашей цитате, вы используете PUT для создания, поскольку нет ресурса, назначенного IRI, и вы все равно хотите создать ресурс. Например, PUT /users/123/password
обычно заменяет старый пароль новым, но вы можете использовать его для создания пароля, если он еще не существует (например, недавно зарегистрированными пользователями или восстановлением заблокированных пользователей).
Я собираюсь приземлиться со следующим:
PUT относится к ресурсу, идентифицированному URI. В этом случае вы обновляете его. Это часть трех глаголов, относящихся к ресурсам - удали и получи два других.
POST - это в основном сообщение в свободной форме, его значение определяется как "вне диапазона". Если сообщение можно интерпретировать как добавление ресурса в каталог, это будет нормально, но в основном вам нужно понимать сообщение, которое вы отправляете (публикуете), чтобы знать, что произойдет с ресурсом.
Поскольку PUT, GET и DELETE относятся к ресурсу, они также по определению идемпотентны.
POST может выполнять другие три функции, но тогда семантика запроса будет потеряна для посредников, таких как кэши и прокси. Это также относится к обеспечению безопасности ресурса, поскольку URI сообщения не обязательно указывает на ресурс, к которому он применяется (хотя может).
PUT не должен быть творением; служба может выдать ошибку, если ресурс еще не создан, но в противном случае обновите его. Или наоборот - он может создавать ресурс, но не разрешать обновления. Единственное, что требуется от PUT - это то, что он указывает на конкретный ресурс, а его полезная нагрузка - это представление этого ресурса. Успешный PUT означает (исключая помехи), что GET будет получать тот же ресурс.
Изменить: еще одна вещь - PUT может создавать, но если это так, то идентификатор должен быть естественным ID - AKA адрес электронной почты. Таким образом, когда вы PUT дважды, второй будет обновлением первого. Это делает его идемпотентным.
Если идентификатор сгенерирован (например, новый идентификатор сотрудника), то второй PUT с тем же URL-адресом создаст новую запись, которая нарушает идемпотентное правило. В этом случае глаголом будет POST, а сообщение (не ресурс) будет создавать ресурс, используя значения, определенные в этом сообщении.
Вот простое правило:
PUT to URL должен использоваться для обновления или создания ресурса, который может быть расположен по этому URL.
POST to URL должен использоваться для обновления или создания ресурса, который находится по какому-то другому ("подчиненному") URL или не может быть обнаружен через HTTP.
Для меня ключом к пониманию разницы было понимание того, кто определяет идентификатор ресурса:
Пример (с некоторой адресной службой)
POST (sever creates new resource)
client server/addresses // NOTE: no ID in the request
| |
| --{POST address data}--> |
| |
| <--{201, created addresses/321} | // NOTE: resource ID in the reply
| |
PUT (sever sets data of resource, creating it if necessary)
client server/addresses/321 // NOTE: *you* put the ID here!
| |
| --{PUT address data (to 321)}-->|
| |
| <--{201, created } | // NOTE: resource ID not required here
| |
Ниже есть много отличных ответов с подробными подробностями, но это помогло мне перейти к сути.
Большую часть времени вы будете использовать их так:
- POST ресурс в коллекцию
- PUT ресурс, идентифицируемый коллекцией /:id
Например:
- ПОСТ / предметы
- PUT / items / 1234
В обоих случаях тело запроса содержит данные для ресурса, который будет создан или обновлен. Из названий маршрутов должно быть очевидно, что POST не идемпотентен (если вы вызываете его 3 раза, это создаст 3 объекта), но PUT является идемпотентом (если вы вызываете его 3 раза, результат одинаков). PUT часто используется для операции "upsert" (создание или обновление), но вы всегда можете вернуть ошибку 404, если хотите использовать ее только для изменения.
Обратите внимание, что POST "создает" новый элемент в коллекции, а PUT "заменяет" элемент по заданному URL-адресу, но это очень распространенная практика - использовать PUT для частичных изменений, то есть использовать его только для обновления существующих ресурсов и изменять только включенные поля в теле (игнорируя другие поля). Это технически неверно, если вы хотите быть REST-purist, PUT должен заменить весь ресурс, и вы должны использовать PATCH для частичного обновления. Лично меня не волнует, насколько поведение ясное и согласованное на всех ваших конечных точках API.
Помните, что REST - это набор соглашений и руководств, упрощающих работу вашего API. Если у вас сложный обходной путь только для того, чтобы установить флажок "RESTfull", значит, вы побеждаете цель;)
Методы запроса GET, PUT и DELETE - это операции CRUD (создание, чтение, обновление и удаление), то есть операции управления данными, в отношении состояния целевого ресурса (того, который определяется URI запроса):
- GET должен читать состояние целевого ресурса;
- PUT должен создавать или обновлять состояние целевого ресурса;
- DELETE должен удалить состояние целевого ресурса.
Другой метод запроса POST. Он не должен создавать состояние целевого ресурса, такого как PUT, потому что это операция процесса с целью более высокого уровня, чем CRUD (см. RFC 7231, § 4.3.3). Процесс может создать ресурс, но отличный от целевого ресурса, в противном случае следует использовать метод запроса цели нижнего уровня PUT, так что даже в этом случае это не делает его операцией CRUD.
Разница между операциями CRUD (GET, PUT и DELETE в HTTP) и операциями без CRUD (POST в HTTP) - это разница между абстрактными типами данных и объектами, которые Алан Кей подчеркивал в большинстве своих выступлений и в своей статье ACM http://worrydream.com/EarlyHistoryOfSmalltalk/:
Что я получил от Simula, так это то, что теперь вы можете заменить привязки и задания целями. Последнее, что вы хотели бы от любого программиста, - это возиться с внутренним состоянием, даже если оно представлено образно. Вместо этого объекты должны быть представлены как сайты более высокого уровня поведения, более подходящие для использования в качестве динамических компонентов.
[…] К сожалению, большая часть того, что сегодня называют "объектно-ориентированным программированием", представляет собой просто старое программирование с более причудливыми конструкциями. Многие программы загружаются операциями "в стиле присваивания", которые теперь выполняются более дорогими присоединенными процедурами.
[…] Заявления о назначении - даже абстрактные - выражают цели очень низкого уровня, и для выполнения чего-либо потребуется их больше. […] Другой способ подумать обо всем этом: хотя позднее связывание автоматического выделения памяти не делает ничего, что не может сделать программист, его присутствие приводит как к более простому, так и к более мощному коду. ООП - это стратегия позднего связывания для многих вещей, и все они вместе сдерживают хрупкость и рост размеров намного дольше, чем старые методологии.
Предполагается, что семантика различна, в том смысле, что "PUT", как и "GET", считается идемпотентным - это означает, что один и тот же точный запрос PUT можно выполнить несколько раз, и результат будет таким, как если бы вы выполняли его только один раз.
Я опишу условные обозначения, которые, на мой взгляд, наиболее широко используются и наиболее полезны:
Когда вы помещаете ресурс по определенному URL-адресу, происходит следующее: он должен сохраняться по этому URL-адресу или что-то в этом роде.
Когда вы размещаете POST на ресурсе по определенному URL-адресу, вы часто публикуете связанную информацию на этот URL-адрес. Это означает, что ресурс по URL уже существует.
Например, когда вы хотите создать новый поток, вы можете положить его на какой-нибудь URL. Но когда вы хотите отправить сообщение в существующий поток, вы отправляете его URL.
Что касается изменения свойств потока, вы можете сделать это с помощью PUT или POST. В основном, используйте "PUT" только тогда, когда операция идемпотентна, в противном случае используйте POST.
Однако обратите внимание, что не все современные браузеры поддерживают HTTP-глаголы, кроме GET или POST.
Если вы знакомы с операциями с базами данных, есть
- Выбрать
- Вставить
- Обновить
- удалять
- Объединить (обновить, если уже существует, еще вставить)
я использую PUT
для слияния и обновления, как операции и использование POST
для вставок.