Re: повторная отправка POST запросов ?

Илья Шипицин chipitsine на gmail.com
Ср Дек 25 21:05:51 UTC 2019


чт, 26 дек. 2019 г. в 01:13, Maxim Dounin <mdounin на mdounin.ru>:

> Hello!
>
> On Thu, Dec 26, 2019 at 12:32:04AM +0500, Илья Шипицин wrote:
>
> > ср, 25 дек. 2019 г. в 23:20, Maxim Dounin <mdounin на mdounin.ru>:
> >
> > > Hello!
> > >
> > > On Wed, Dec 25, 2019 at 02:58:15PM +0500, Илья Шипицин wrote:
> > >
> > > > ср, 25 дек. 2019 г. в 14:38, Sergey Kandaurov <pluknet на nginx.com>:
> > > >
> > > > >
> > > > > > On 24 Dec 2019, at 23:35, Илья Шипицин <chipitsine на gmail.com>
> wrote:
> > > > > >
> > > > > > привет!
> > > > > >
> > > > > > допустим, такая ситуация. есть POST запрос, у него есть хедеры и,
> > > > > собственно, тело запроса. мы отправили хедеры на бекенд, тело не
> успели
> > > > > отправить, и бекенд нам сделал TCP RST.
> > > > > >
> > > > > > должен ли такой POST повторно отправляться, если не указан
> > > > > non_idempotent ? (судя по моим экспериментам - не отправляется. но
> ведь
> > > > > тело не было отправлено ? значит мы должны попасть под условие, что
> > > такой
> > > > > запрос можно отправить повторно ?)
> > > > >
> > > > > Как только мы успешно установили соединение и перешли к отправке
> > > запроса
> > > > > (не важно, успели начать отправку тела или нет), запрос считается
> > > > > отправленным,
> > > > > т.к. в общем случае мы не знаем, был ли он обработан или нет.
> > > > >
> > > >
> > > > я предлагаю такую логику.
> > > > бекенд умеет отличать полностью полученный запрос от неполного
> запроса
> > > > (например, по Content-Length)
> > > > навряд ли бекенд будет обрабатывать неполностью полученный запрос
> > > >
> > > > и считать отправленными только полностью отправленные запросы
> > >
> > > Считать-то можно, но у бекенда может быть своё мнение по этому
> > > вопросу.  Каких-либо явных утверждений в RFC 2616 / RFC 7231,
> > > которые бы говорили о том, что так можно - я в своё время не
> > > нашёл.  И по факту так скорее всего нельзя, так как на тело
> > > бекенду во многих случаях может быть наплевать.
> > >
> >
> > есть достаточно странный кейс, когда отправляется POST без тела. не
> > конкретно в наших приложениях, а в принципе.
> > я по некоторым разбирался, зачем так делают (ну то есть, можно же GET, но
> > специально сделали POST). ответ меня поразил -
> > по RFC нельзя кешировать POST. ну и чтобы наверняка без кеша, мы выбрали
> > POST )) ну а тело ... надо не надо было
> >
> > в описанном выше случае, действительно, тело (запроса) не предполагалось.
> >
> > если тело предполагается, но не было отправлено, допустим бекенд
> вменяемый,
> > что вполне может быть. он запрос не обработал.
> > можно ретраить.
> >
> > каких-то явных противоречий в этом не вижу
>
> Явных противоречий тут и нет: скорее всего бекенд смотрит на тело,
> и в тех немногих случаях, когда мы точно знаем, что оно отправлено
> не полностью - скорее всего можно ретраить.
>

> Однако проблем тут две:
>
> - "Скорее всего можно" - не значит "точно можно", наступить на
>   ситуацию, когда бекенд на тело не смотрит - на практике вполне
>   можно.  И каких-либо явных причин требовать от бекенда, чтобы
>   смотрел - я, как я уже писал выше, не вижу, и если у такого
>   бекенда вдруг что-то пойдёт не так - виноват будет nginx.  (Если эти
>   причины вдруг есть - с удовольствием ознакомлюсь с соответствующей
>   цитатой из RFC.)
>
> - Условие "когда мы точно знаем" не выполняется приблизительно
>   никогда: в подавляющем большинстве случаев тело вместе с
>   запросом уже сложено в буфер сокета, и что там с ним стало
>   дальше - узнать невозможно.  То есть мы про микрооптимизацию
>   оцень небольшого процента запросов.
>
>
ну вот у меня ситуация, когда я знаю, что можно.
рассказываю.

берем IIS. на нем хостим ASP.NET
ASP.NET хостится в т.н. AppPool, у этого пула есть режим "пул остановлен"

можно настроить пул на HttpLevel, либо на TcpLevel, в первом случае
остановленный пул отдает 503, во втором tcp rst.

вы хотели RFC ? оно есть у меня. смотрите, есть такой хидер Expect. смотрим
RFC, там сказано, что он End-to-End.
итак, рассмотрим цепочку

Браузер --> nginx --> IIS

браузер посылает Expect: 100-Continue, по RFC nginx должен его доставить до
IIS ? но этого не происходит.
IIS (и http.sys под капотом) ответил бы Expect, и у nginx была бы инфа, что
запрос не успел отправиться

но nginx не отправляет Expect.

и POST улелает в остановленный пул. если пул настроен на HttpLEvel, то пул
отдает 503 уже после отправки (были бы Expect-ы, отдал бы до).

ок, меняем режим пула на TcpLevel, пул должен сделать tcp rst. и он его
сделает. но! нюанс. после отправки хидеров.
объяснение простое, на порту, на котором слушает IIS, могут быть несколько
приложений (пулов), чтобы понять, в какой именно пул мы попали, нужно поле
Host.

но я точно знаю, что tcp rst идет до отправки тела. и nginx это точно знает.



а разработчики, которые пишут идеальные приложения ... ну я тоже люблю
фантазировать.


> Вместе эти две проблемы привели меня в своё время к выводу, что не
> стоит тут пытаться что-то наоптимизировать, кому надо - сделают
> правильно с защитой на уровне приложения, кому не надо - получают
> гарантированно корректное поведение из коробки.
>
> --
> Maxim Dounin
> http://mdounin.ru/
> _______________________________________________
> nginx-ru mailing list
> nginx-ru на nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-ru
----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mailman.nginx.org/pipermail/nginx-ru/attachments/20191226/3094606d/attachment-0001.htm>


Подробная информация о списке рассылки nginx-ru