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

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

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

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

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

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

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

Ответы [ 32 ]

52 голосов
/ 11 января 2012

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

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

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

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

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

Короче говоря:

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

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

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

PUT Можно придумать что-то похожее на "ОБНОВЛЕНИЕ СТУДЕНЧЕСКОГО НАСТРОЙКА address =" abc ", где id =" 123 ";

POST Вы можете придумать что-то вроде «ВСТАВИТЬ В СТУДЕНТА (имя, адрес)» («abc», «xyzzz»);

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

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

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

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

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

42 голосов
/ 14 июня 2013

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

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

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

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

POST versus PUT

38 голосов
/ 02 августа 2012

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

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

PUT x (если x идентифицирует ресурс ): «Заменить содержимое ресурса, обозначенного x, моим содержанием.»

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

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

37 голосов
/ 15 октября 2017

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

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

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

POST:

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

PUT:

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

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

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

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

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

35 голосов
/ 26 февраля 2012

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

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

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

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

27 голосов
/ 25 марта 2011

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

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

21 голосов
/ 14 февраля 2017

Очень просто я беру пример с временной шкалы Facebook.

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

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

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

В одну строку используйте POST , чтобы добавить новую запись в базу данных и PUT в обновить что-то в базе данных .

20 голосов
/ 08 февраля 2012

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

...