Перенаправление до завершения загрузки POST
У меня есть форма с загрузкой файлов. Файлы для загрузки на самом деле являются фотографиями и видео, поэтому они могут быть довольно большими. У меня есть логика, которая на основе заголовков и первых 1 КБ может определить, будут ли остальные обработаны или немедленно отклонены. В последнем случае я бы хотел перенаправить клиента на страницу ошибки, не дожидаясь окончания загрузки.
Дело в том, что просто отправка ответа до завершения POST, похоже, не работает. Перенаправление игнорируется, и если я закрываю соединение, браузер выдает ошибку "Сброс соединения по одноранговой сети".
Таким образом, вопрос: возможно ли это сделать в чистом HTTP (без JavaScript на стороне клиента), и если да, то как?
3 ответа
Протокол HTTP/1.1 допускает это, просто очень странным и запутанным способом. Вам необходимо применить следующие 3 шага:
- Немедленно (внезапно) закройте соединение, сохраните флаг на стороне сервера для сеанса клиента
- Используйте флаг, чтобы обнаружить попытку повторно отправить те же данные формы, спецификация рекомендует клиенту сделать это автоматически
- Отправить статус ошибки с перенаправлением (например, 302 временно перемещен)
Это ДОЛЖНО работать, потому что, как указано ниже, клиент, как ожидается, попытается повторить соединение хотя бы один раз после неожиданного отключения. При повторной попытке (попытках) ожидается только отправка заголовков, затем ожидание и наблюдение за ответом об ошибке и прекращение отправки тела, если оно получено.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html
8.2.4 Поведение клиента, если сервер преждевременно закрывает соединение
Если клиент HTTP/1.1 отправляет запрос, который включает тело запроса, но не включает поле заголовка запроса Expect с ожиданием "100-continue", и если клиент не подключен напрямую к серверу происхождения HTTP/1.1 и если клиент видит закрытое соединение до получения какого-либо статуса от сервера, клиент ДОЛЖЕН повторить запрос. Если клиент повторяет этот запрос, он МОЖЕТ использовать следующий алгоритм "двоичного экспоненциального отката", чтобы быть уверенным в получении надежного ответа:
1. Initiate a new connection to the server 2. Transmit the request-headers 3. Initialize a variable R to the estimated round-trip time to the server (e.g., based on the time it took to establish the connection), or to a constant value of 5 seconds if the round- trip time is not available. 4. Compute T = R * (2**N), where N is the number of previous retries of this request. 5. Wait either for an error response from the server, or for T seconds (whichever comes first) 6. If no error response is received, after T seconds transmit the body of the request. 7. If client sees that the connection is closed prematurely, repeat from step 1 until the request is accepted, an error response is received, or the user becomes impatient and terminates the retry process.
Если в какой-то момент получен статус ошибки, клиент
- SHOULD NOT continue and - SHOULD close the connection if it has not completed sending the request message.
Gotchas:
- Это то, что спецификация говорит, что браузеры должны делать. Кто знает, что на самом деле делают браузеры в этом случае? Не я. Вам нужно будет выполнить несколько тестов.
- В спецификации особо упоминается, что это поведение применяется только "если клиент не подключен напрямую к серверу происхождения HTTP/1.1". Это кажется действительно странным требованием, которое на практике означает, что вам может понадобиться подделать заголовки ответа вашего сервера, чтобы представить себя прокси-сервером или сервером HTTP/1.0.
- Некоторые промежуточные протоколы, такие как fast-cgi, могут не активировать ваш скрипт, пока запрос не будет выполнен. В этом случае вам действительно понадобится настоящий низкоуровневый сервер сокетов.
- Весь этот процесс запутан и запутан и может даже не работать. На мой взгляд, вам лучше использовать AJAX. Тем не менее, вы спросили, можно ли это сделать без JS.
Взгляните на билет django № 10850 - "Невозможно остановить загрузку большого файла в середине потока". Не решает проблему, но, по крайней мере, это должно помочь вам понять это.
- используйте расширение PCEL uploadprogress, если вы используете apache
- Создайте файл для опроса мета через Ajax и верните true или false в зависимости от вашего состояния, вы также можете получить файл temp_name и проверить мета 1kb.
- вызов ajax должен быть связан с функцией, которая использует заголовки метаобновления HTML для перенаправления или остается до завершения загрузки.
Ознакомьтесь с примерами загрузки.