Почему HTTP-операции должны быть идемпотентными, когда у нас есть TCP / IP?

#http #networking #rest #tcp

#http #сеть #rest #tcp

Вопрос:

Почему нам нужно, чтобы HTTP GET, PUT или DELETE были идемпотентными, если TCP / IP является надежным протоколом, который будет повторять запросы от нашего имени?

Ответ №1:

TCP / IP не повторяет запросы, он повторно передает исходные пакеты, которые составляют каждый запрос, если это необходимо.

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

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

Эти сбои могут произойти — промежуточный брандмауэр мог отключить соединение, пока сервер обрабатывал операцию. Сервер не будет знать, что это произошло, как только он получит запрос, он должен продолжить независимо.

Комментарии:

1. Какой тип сбоя запроса должен быть повторен на уровне HTTP, но не на уровне пакета?

2. 502 неисправных шлюза, 504 тайм-аута шлюза, 500 внутренних ошибок сервера (скажем, истекло время ожидания базы данных) Это то, что вызывает страшную «тройную публикацию» на форумах, reddit и т.д.

3. Отличный момент для тайм-аутов. Итак, мы говорим, что TCP / IP гарантирует, что сервер получит наш запрос, но у клиента может истечь время ожидания, прежде чем сервер выполнит операцию. Клиенты ожидают, что смогут повторить попытку позже, не дублируя исходную операцию. Не могли бы вы, пожалуйста, обновить ответ этим объяснением?

4. @Gili TCP не гарантирует, что две стороны договорятся о том, был ли обмен данными или нет. Если вы отправляете запрос и соединение прерывается до того, как вы получите ответ, вы не знаете, обработала ли другая сторона запрос или нет.

5. @DavidSchwartz Хороший пример!

Ответ №2:

HTTP-операции GET, PUT и DELETE являются идемпотентными, потому что в некоторых режимах сбоя сети клиент не может знать, завершен ли запрос и насколько полно.

Например, если клиент запрашивает УДАЛЕНИЕ ресурса, но сервер закрывает соединение до того, как клиент получит полный ответ, клиент не знает, был ли ресурс удален или нет. Затем у клиента возникает дилемма: возможно, операция завершилась неудачно, и в этом случае УДАЛЕНИЕ должно быть повторно отправлено, чтобы перевести приложение в желаемое состояние. Но, возможно, это удалось; сработает ли отправка того же запроса на удаление, если я повторю попытку? Возможно, это сработает. Возможно, это вернет ошибку 500 (что только добавит путаницы клиенту). Возможно, это будет применимо к другому ресурсу! Требование идемпотентности позволяет клиенту быть уверенным в том, что он может повторить запрос и заставить его сработать. Это не означает, что вы получите точно такой же ответ; на первый запрос может быть получено 200 OK, а на второй 404 Not Found или 410 Gone. Но клиенту не нужно беспокоиться о непреднамеренных побочных эффектах от повторных попыток.

Комментарии:

1. То есть вы говорите, что HTTP является идемпотентным для того, чтобы иметь дело с неправильно настроенными соединениями TCP / IP? Я не думаю, что вы можете получить сброс соединения при нормальных условиях.

2. HTTP разработан для хорошей работы даже в условиях, когда перезагрузки очень «нормальные». Дело не в неправильной конфигурации; речь идет о правильной работе даже при большой нагрузке. Любой крупный веб-сайт научился мириться с тем, что какая-то часть их компьютеров будет постоянно выходить из строя. HTTP позволяет им разрабатывать приложения, которые могут выжить в этой реальности.

3. cf w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4 TCP-соединения, особенно стиль запроса / ответа, могут иметь очень неприятные проблемы с синхронизацией, которые не имеют ничего общего с конфигурацией.

Ответ №3:

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

HTTP-Идемпотентность:

Идемпотентность (википедия) означает, что отправка одного и того же HTTP-запроса 10 раз имеет тот же эффект, что и выполнение его один раз.

Надежность TCP:

Если вы потеряете пакет в потоке TCP, он будет передан повторно. Но application-protocol (HTTP) не знает, что TCP должен был повторно передавать пакеты.

Даже если отдельный пакет, содержащий полный HTTP-запрос, повторно передается TCP 10 раз, браузер / сервер увидит только один HTTP-запрос. Причина повторной передачи TCP заключается в потере пакетов, но прикладные протоколы (такие как HTTP) не знают, что TCP должен был повторно передавать. Они кажутся одинаковыми запросами с потерей пакетов или без нее

Комментарии:

1. @Mike: Я понимаю разницу. Я не понимаю, зачем вам нужно было повторять один и тот же запрос (ПОМЕСТИТЬ или УДАЛИТЬ) 10 раз, если это не было связано с отброшенным пакетом.

2. @Gili, в этом-то и суть. Вам не нужно повторять HTTP PUT или любую другую HTTP-команду из-за повторной передачи пакета. HTTP-запросы повторяются из-за поведения человека (или робота) (нажатие перезагрузки в их браузере)…

3. @Mike: Вы даете хорошее объяснение идемпотентности и надежности TCP, но не можете объяснить, почему клиентам вообще нужно повторять запрос (пользователи / роботы не повторяют операцию без причины).

4. @Gili, я даже не понимаю, почему это важно; пожалуйста, поясните, почему это важно

5. @Mike, почему мы должны защищать пользователей от повторения запроса на покупку? Может быть, они действительно хотят приобрести один и тот же товар дважды? Я хочу сказать, что если вы не понимаете, почему запросы повторяются, неясно, почему вы должны защищаться от этого. Без конкретных примеров это воспринимается как решение бизнес-логики, а не как нечто, относящееся к HTTP-уровню.