Обработка 100-продолжить при перенаправлении запроса POST от контроллера веб-API

У меня есть ApiController который отвечает на запрос POST, перенаправляя его через код состояния HTTP 307. Он делает это, используя только информацию из заголовка, поэтому тело запроса не требуется для этого действия. Это действие эквивалентно:

public HttpResponseMessage Post() {
    var url;
    // Some logic to construct the URL
    var response = new HttpResponseMessage(HttpStatusCode.TemporaryRedirect);
    response.Headers.Location = new System.Uri(url);
    return response;
}

Это достаточно просто, но есть одно улучшение, которое я хотел бы сделать. Тело запроса может содержать большой объем данных, поэтому я хотел бы использовать код состояния HTTP 100, чтобы сделать этот запрос более эффективным. С контроллером, как сейчас, разговор может выглядеть так:

> POST /api/test HTTP/1.1
> Expect: 100-continue
> ...

< HTTP/1.1 100 Continue

> (request body is sent)

< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...

Поскольку тело запроса не требуется для действия перенаправления, я хотел бы иметь возможность сократить разговор до:

> POST /api/controller HTTP/1.1
> Expect: 100-continue
> ...

< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...

Большую часть дня я потратил на изучение того, как этого добиться, и не смог найти решение. В своем исследовании я узнал:

  • Когда ApiController действие выполняется, то 100 Continue уже отправлено.
  • Когда ApiController построен, 100 Continue уже отправлено.
  • Когда HttpApplication "s PreRequestHandlerExecute событие срабатывает, 100 Continue ответ не был отправлен.
  • Когда DelegatingHandler выполняет, 100 Continue уже отправлено.

Исходя из этого, лучшее решение, которое я нашел до сих пор, - это создать HttpModule который использует RouteData на RequestContext переопределить ответ, когда ApiController речь идет о получателе запроса. Однако это далеко от идеального решения по нескольким причинам (разделение кода, отсутствие использования привязки параметров Web API и обход дополнительной логики в AuthorizeAttribute на ApiController).

Кажется, что должно быть лучшее решение для этого, но я нашел очень мало информации о том, как правильно обращаться с Expect: 100-continue заголовок в приложении веб-API. Какой бы самый простой способ реализовать это ApiController правильно обращаться с Expect: 100-continue заголовок?

2 ответа

... Вы уверены, что вам нужна эта оптимизация?

Если вы используете IIS 6, вам нужно перейти в режим совместимости с IIS 5 и написать фильтр ISAPI ReadRawData / SendRawData. Расширение ISAPI не может быть рассмотрено по причинам, изложенным ниже в моем ответе. (Если вы используете IIS 5 или ниже, пусть Бог помилует вашу душу)

Если вы используете IIS 7+, возможно, вам удастся написать собственный модуль IIS.

Вы правы, полагая, что к тому времени, когда контроллер включится, ответ уже будет отправлен, потому что Web API живет внутри ASP.NET; этот ответ обрабатывается ядром IIS.

Некоторый легкий материал для чтения

HTTP.SYS IIS и 100 продолжить

Дэвид Ван

"100 continue", например "400 Bad Request" или "Kernel Response Cache Hit", является особенным в том смысле, что HTTP.SYS прозрачно обрабатывает его в режиме ядра, не уведомляя пользовательский режим ни о чем. вывод - они могут только генерировать вывод ответа, но не видеть результаты вывода ответа. Таким образом, расширение ISAPI никогда не сможет взаимодействовать с запросами, которые генерируют ответы "100 продолжить" или сами "100 продолжить" для их подавления.

На IIS6 единственный способ внедрить обработку в пользовательском режиме в эти прозрачные обработки запросов HTTP.SYS - это запустить в режиме совместимости IIS5 и использовать фильтр ISAPI ReadRawData / SendRawData. ReadRawData заставляет HTTP.SYS пересылать необработанные данные из сети в пользовательский режим для фильтрации PRIOR для анализа выходных данных пользовательского режима в HTTP-запросах для помещения в очереди.

Конечно, этот метод полностью отрицает цель запуска IIS6 с пулами приложений и изоляцией процесса (один сбой в этом процессе фильтрации пользовательского режима останавливает весь сервер)... но таков компромисс на стороне сервера, когда клиент глючит...

К вашему сведению: этот подход не будет работать на Vista Server/IIS7. HTTP.SYS больше не будет передавать необработанные данные из сети в пользовательский режим для фильтрации перед синтаксическим анализом, поэтому для кода пользовательского режима будет невозможно узнать, что произошел запрос, который запускает автоматическое "100 продолжить".


редактировать

Haacked Http Web Request Expect 100 Продолжить

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

Одним из способов реализации этого было бы написать свой собственный IHttpControllerSelector который назначит запрос правильному контроллеру на основе заголовков запроса.

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

Другие вопросы по тегам