Требуется ли HTTP-запрос PUT для включения тела?

92

Мне трудно найти конкретную спецификацию этого в стандарте. У меня есть HTTP-клиент, который не включает Content-Length: 0заголовок при выполнении запроса PUT, где я не указываю тело, и сервер, который сбивает с толку такие запросы, и мне интересно, какую программу я должен винить.

Marijn
источник
Я могу спросить, зачем вам редактировать вопрос из 2009 года?
zmuci
@zmuci Для лучшего форматирования?
Константин Ван

Ответы:

83

HTTP-запросы имеют тело, если у них есть заголовок Content-Length или Transfer-Encoding ( RFC 2616 4.3 ). Если у запроса нет ни того, ни другого, у него нет тела, и ваш сервер должен рассматривать его как таковой.

Тем не менее, для запроса PUT необычно не иметь тела, и поэтому, если бы я проектировал клиента, который действительно хотел отправить пустое тело, я бы передал Content-Length: 0. Действительно, в зависимости от чтения POST и определения методов PUT ( RFC 2616 9.5, 9.6 ) можно было бы возразить, что тело подразумевается как обязательное, но разумный способ не обрабатывать тело - это принять тело нулевой длины.

бдонлан
источник
Как подразумевают коды состояния HTTP 200 («ОК»), 201 («Создан») и 204 («Нет содержимого»), PUTзапрос в основном предназначен для создания или обновления файла на сервере. И нет ничего незаконного в том, что файл пустой, не так ли?
Константин Ван
5
@bdonlan вы сказали, что PUT с пустым телом необычен, но если я хочу включить или отключить пользователя, мне не понадобится тело в моем запросе, на самом деле запросы PUT могут быть "/ users / {id} / enable" или "/ users / {id} / disable".
Винисиус де Алмейда
@ViniciusdeAlmeida Эти ресурсы не подходят, если вы пытаетесь придерживаться стандартов REST. disableи enableявляются глаголами. В этом случае я, вероятно, предпочел бы использовать PATCHна /users/{id}конечной точке.
раздавить
42

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

Пример размещения без тела: дать пользователю дополнительное разрешение.

PUT / admin / users / {имя пользователя} / разрешение / {разрешение}

Благословенный Компьютерщик
источник
2
Собственно моя проблема! Я пришел к такому же выводу. Но, строго говоря, это противоречит RFC, где, хотя и не упоминается явно, тело считается существующим. Это могло вызвать проблемы, но, по моему опыту, все современные веб-серверы / фреймворки будут работать.
Agoston Horvath
Я в аналогичном случае, мне нужен API, чтобы связать существующий ресурс с пользователем. Я мог бы использовать POST users /: userId / resources с resourceId в теле. Или, скорее, это подойдет PUT users /: userid / resources /: resourceId. Большая разница здесь в том, что первый API должен быть неидемпотентным, поэтому я могу дважды связать один и тот же ресурс с пользователем. вызов PUT должен сбросить предыдущую ассоциацию
Кармине Ингальди
5

Стандарт IETF не требует наличия тела, хотя длина содержимого должна быть равна 0, если тела нет. Используйте метод, подходящий для того, что вы делаете. Если бы вы поместили это в код, учитывая

int x;
int f(){ return x; }

и удаленная переменная с именем r.

Сообщение эквивалентно

r=f();

Пут эквивалентен

r=x;

и получить эквивалентно

x=r;
abc
источник
1
Это самый ясный пример PUT vs POST, который я когда-либо читал, хотя и не по теме
цифровая иллюзия
Если запрос имеет заголовок Content-Length, значит, у него есть тело. Это может быть пустое тело, но все же тело. В отличие от запроса без заголовка Content-Length, у которого вообще нет тела, даже не пустого. Итак, да, запрос PUT, строго говоря, должен иметь тело. Всегда.
Пол Грок,
Также ваша аналогия с POST меня полностью сбивает с толку. Если я попытаюсь придерживаться остальной части вашей аналогии, это должно быть больше похоже на то, что сервер имеет, int f(int* resource, int body);а затем будет вызываться POST f(&r, x);- что может делать или не делать rто, что сервер считает подходящим. Но он также может возвращать вещи, так что ... может быть, больше похоже y = f(&r, x);.
Пол Грок,
0

Что помещается (в смысле глагола) на сервер, если нет контента? В спецификации содержимое называется «закрытой сущностью», но запрос без содержимого не будет иметь закрытой сущности и, следовательно, ничего не будет помещать на сервер.

Если, конечно, вы не хотите ничего ПОГРУЗИТЬ на сервер, в этом случае вы, вероятно, захотите вместо этого УДАЛИТЬ.

Роб Хруска
источник
1
то, что вы вводите, может быть закодировано в URL-адресе, а не в теле
MikeT
1
PUT empty просто объявляет, что ресурс с данным идентификатором должен существовать на сервере, хотя у него нет содержимого, кроме самого идентификатора. Это совершенно другая семантика от DELETE.
Imre Pühvel
Представьте, что вы хотите ПОСТАВИТЬ ресурс, но принимаете все значения по умолчанию на стороне сервера. Что бы было Content-Length: 0или { }в JSON в качестве тела?
Люк Пуплетт 07
1
Значит, на вашем компьютере нет ни одного пустого файла ?
Константин Ван