HTTP кажется безумно простым протоколом, но это не так; вам следует использовать клиентскую библиотеку HTTP, такую как встроенный _ 1_ клиент.
Проблема в том, что концепция «дайте мне мои данные, а затем закройте их» - это HTTP / 1.0, и она устарела на несколько десятилетий. HTTP / 2.0 и HTTP / 3.0 являются двоичными протоколами, а HTTP / 1.1 имеет тенденцию оставлять соединение открытым. В общем, «читать строки» и даже «использовать Reader» (например, читать символы вместо байтов) - это неправильный способ сделать это, поскольку HTTP не является текстовым протоколом. Я знаю. Похоже, что один. Это не.
Вот очень упрощенный обзор того, как, например, браузер читает ответы HTTP / 1.1:
- Используйте необработанную обработку байтов, потому что содержимое тела HTTP является необработанным (или может быть), поэтому все это обертывается, например,
InputStreamReader
или BufferedReader
не запускается.
- Продолжайте читать, пока не будет прочитан байт 0x0A (в ASCII, символ новой строки), или X байтов и ваш буфер для этого не будет заполнен, где X не является чрезмерно большим. Не хотелось бы, чтобы сервер с плохим поведением или недоразумение при подключении к другой (не HTTP) службе вызвало проблемы с памятью! Разберите эту первую строку как ответ HTTP / 1.1.
- Продолжайте делать этот цикл, чтобы собрать все заголовки. Используйте тот же трюк «у моего буфера есть ограничения», чтобы избежать проблем с памятью.
- Затем проверьте код ответа, чтобы узнать, будет ли тело в ближайшее время. Это HTTP / 1.1, так что вы не можете просто пойти: ну, если соединение закрыто, я думаю, никто не появится. Придет он или нет, зависит в первую очередь от кода ответа.
- Предполагая, что тело существует, прочтите двойной символ новой строки, отделяющий заголовки от тела.
- Если содержимое передается как фрагментированное кодирование (обычное), начните копирование данных в буфер, но проверьте, читаете ли вы весь фрагмент. На самом деле чтение фрагментированной кодировки - это отдельная игра.
- В качестве альтернативы HTTP / 1.1 ТРЕБУЕТ, что, если кодирование по фрагментам не используется, присутствует
Content-Length
. Используйте этот заголовок, чтобы точно знать, сколько байтов нужно прочитать.
- Ни «новая строка», ни «тесное соединение» никогда не могут служить значимым маркером «конца данных» в HTTP / 1.1, так что не делайте этого.
- Затем либо дословно передайте содержимое + заголовки + код возврата запрашивающему коду, либо немного его приукрасите. Например, если заголовок
Content-Type
присутствует и имеет значение text/html; encoding=UTF-8
, вы можете рассмотреть возможность преобразования основных данных в строку через UTF-8 (new String(byteArray, StandardCharsets.UTF_8);
).
Обратите внимание, что я пропустил какое-то странное поведение серверов, потому что в былые времена какой-то глупый браузер делал странные вещи, и теперь это статус-кво (например, запросы диапазона довольно странные), и, конечно же, HTTP2 и HTTP3, которые совершенно разные протоколы.
Кроме того, конечно, в наши дни редко встречаются HTTP-серверы; HTTPS - вот где он, и это тоже совсем другое.
person
rzwitserloot
schedule
12.10.2020
}
? - person Spectric   schedule 12.10.2020BufferedReader#readLine()
он сообщает [возвращает] null, если достигнут конец потока. Я подозреваю, что ваш цикл на самом деле не застрял, он просто ждет дополнительных данных. То, что вы прочитали все доступные данные, не означает, что вы достигли конца потока. - person Charlie Armstrong   schedule 12.10.2020ready()
в качестве решения ... что является плохой идеей. - person Stephen C   schedule 12.10.2020ready()
ненадежно. Возможно, чтоready()
вернетfalse
, когда еще есть данные, но их еще нет из-за сбоя в сети. - person Stephen C   schedule 12.10.2020