ДА или НЕТ: может ли сервер отправить HTTP-ответ, одновременно загружая файл из соответствующего HTTP-запроса?
Если пользователь веб-сайта отправляет HTML-форму с: (1) методом публикации; (2) многочастный / форма-данные-энктип; и (3) большой вложенный файл, может ли сервер загрузить опубликованный файл и отправить сгенерированный сервером HTTP-ответ до завершения загрузки файла, без использования AJAX?
Это довольно плотно. Итак, я написал пример, чтобы проиллюстрировать, что я имею в виду. Допустим, есть форма загрузки изображения с полем заголовка.
<form action="upload-with-caption/" method="post" enctype="multipart/form-data">
<input type="hidden" id="hiddenInfo" name="hiddenInfo" />
File: <input type="file" name="imgFile" id="imgFile" /><br />
Caption: <input type="text" name="caption" id="caption" />
<input type="submit" />
</form>
Я хочу сохранить заголовок в таблице базы данных с определением:
[Files_table]
- file_id [уникальный идентификатор]
- file_caption [varchar (500)]
- file_status [int]
Затем я хочу загрузить файл в /root/{unique-id}/filename.ext
,
file_status сопоставляется с перечислением C# со следующим определением:
enum FileUploadStatus{
Error = 0,
Uploading = 1,
Uploaded = 2
}
Когда форма отправляется, если файл слишком велик для обработки в течение 1 секунды, я хочу отправить веб-странице ответ, в котором говорится, что он загружается в данный момент.
Могу ли я сделать это с помощью одного синхронного сообщения HTTP?
Примечание: я, очевидно, захочу проверить наличие обновлений статуса позже, используя AJAX, но это не то, что задает этот вопрос. Я специально спрашиваю, может ли файл продолжить загрузку после отправки ответа.
2 ответа
HTTP является синхронным протоколом.
Вы не можете отправить ответ, пока не получите весь запрос.
Глядя только на спецификации HTTP (RFC 753x), ответ - Да (и принятый в настоящее время ответ неверен). HTML конкретно, я не думаю, что есть что добавить.
Протокол HTTP/1.1 «полагается на то, что порядок поступления ответов точно соответствует порядку, в котором выполняются запросы по тому же соединению» (). Время не имеет к этому никакого отношения.
Протокол не только допускает ранние ответы, но и семантика некоторых сообщений из категорий 4xx (ошибка клиента) и 5xx (ошибка сервера) фактически предполагает, что ответ будет отправлен до завершения запроса.
Возьмем пример. Если вы собираетесь отправить пять триллионов миллиардов миллионов гигабайт на веб-сервер (предположим, что это число соответствует любым типам данных, используемым для заголовка Content-Length), когда вы ожидаете получить ответ «413 Payload Too Large»? Как можно скорее или только через пару десятков лет, когда завершится передача заявки? Очевидно, чем раньше, тем лучше!
Ответы 2xx (успешно) немного отличаются. Эти ответы «указывают, что запрос клиента был успешно получен, понят и принят» (RFC 7231 §6.3). Ранняя отправка ответа такого типа может запутать клиента.
Вместо этого то, что вы, вероятно, захотите отправить обратно в качестве предварительного ответа, относится к категории 1xx (информационная). Они называются «промежуточными ответами», предназначенными для замены, но не устаревания окончательного ответа.
Класс кода состояния 1xx (информационный) указывает на промежуточный ответ для сообщения о состоянии соединения или ходе выполнения запроса до завершения запрошенного действия и отправки окончательного ответа.
Более одного ответного сообщения на запрос появляется только тогда, когда один или несколько информационных ответов предшествуют окончательному ответу на тот же запрос.
В RFC 7231 §5.1.1 есть отличный пример, когда клиент собирается отправить «предположительно большое» сообщение, но вместо того, чтобы сразу отправить тело после заголовка, клиент включает
Expect: 100-continue
заголовок, а затем переходит в короткую паузу, ожидая, что сервер либо отклонит сообщение, либо предложит клиенту продолжить, отвечая на промежуточный ответ «100 Continue». Это потенциально избавляет клиента от необходимости передавать байты впустую. Умная!
Наконец, я долго и упорно думал о том, когда мы когда-нибудь захотим отправить ответ 2xx (Successful) обратно клиенту до того, как запрос будет завершен? Я могу придумать только один сценарий - и это, конечно, не обычный случай, но я собираюсь его указать: если сервер израсходовал достаточно запросов, чтобы принять меры, и сервер хочет отбросить оставшиеся body, потому что остаток достаточно велик и в то же время бесполезен для сервера, затем ответьте 202 Accepted и включите заголовок «Connection: close».
Это, очевидно, не очень хорошо для повторного использования соединения, а также может легко привести к путанице клиентов, поэтому выигрыш, почему мы реагируем раньше, должен быть 1) достаточно выгодным, чтобы уменьшить накладные расходы на установление нового соединения, 2) достаточно выгодным, чтобы компенсировать опасность сбоя клиентов, которые не были готовы к быстрому реагированию, и 3) быть хорошо задокументированными.
Заголовок «Connection: close» явно указывает клиенту прекратить отправку запроса (RFC 7230 §6.3). И из-за кадрирования сообщения соединение в любом случае разорвано, поскольку нет возможности возобновить связь с новой парой обмена сообщениями по тому же соединению. С технической точки зрения, клиент может безошибочно прервать передачу по частям (RFC 7230 §4.1) и, таким образом, сохранить соединение, но это детали и в общем случае неприменимо.