Программирование сокетов Java — ошибка 301 с HTTP 1.1

Я только начинаю изучать программирование сокетов на Java и уже столкнулся с необычным поведением. Вот фрагмент кода

writer.println("GET " + path + " " + protocol);
//writer.println();
writer.println("Host: " + hostname);
writer.println();
writer.flush();

Это даст мне код «301 Moved Permanently» как с HTTP 1.1, так и с 1.0. Если я раскомментирую пустую строку между запросом и именем хоста

writer.println("GET " + path + " " + protocol);
writer.println();
writer.println("Host: " + hostname);
writer.println();
writer.flush();

Это дало бы мне "HTTP/1.1 400 Bad Request" для HTTP 1.1 и "HTTP/1.1 200 OK" для HTTP 1.0.

Почему у него такое поведение? Это происходит из-за того, что у нас есть запрос в HTTP 1.0, а ответ в HTTP 1.1?

Спасибо.


person hvuong91    schedule 17.05.2016    source источник


Ответы (1)


Это даст мне код «301 Moved Permanently» как с HTTP 1.1, так и с 1.0.

код состояния HTTP 301 – это перенаправление на новый URL-адрес:

Запрошенному ресурсу был назначен новый постоянный URI, и любые будущие ссылки на этот ресурс СЛЕДУЕТ использовать один из возвращенных URI. Клиенты с возможностями редактирования ссылок должны автоматически повторно связывать ссылки с Request-URI на одна или несколько новых ссылок, возвращенных сервером, если это возможно. Этот ответ можно кэшировать, если не указано иное.

Новый постоянный URI ДОЛЖЕН быть указан в поле Location в ответе. Если метод запроса не был HEAD, сущность ответа ДОЛЖНА содержать короткую гипертекстовую заметку с гиперссылкой на новые URI. .

Если код состояния 301 получен в ответ на запрос, отличный от GET или HEAD, пользовательский агент НЕ ДОЛЖЕН автоматически перенаправлять запрос, если он не может быть подтвержден пользователем, поскольку это может изменить условия, при которых был выдан запрос.

Примечание. При автоматическом перенаправлении запроса POST после получения кода состояния 301 некоторые существующие пользовательские агенты HTTP/1.0 ошибочно изменят его на запрос GET.

Сервер сообщает вам, что URL-адрес, на который вы отправили запрос GET, больше недействителен. Вам нужно извлечь значение заголовка Location из ответа сервера, а затем повторить тот же запрос на указанный URL.

Это дало бы мне «HTTP/1.1 400 Bad Request» для HTTP 1.1 и «HTTP/1.1 200 OK» для HTTP 1.0.

Почему у него такое поведение? Это происходит из-за того, что у нас есть запрос в HTTP 1.0, а ответ в HTTP 1.1?

Заголовок Host является необязательным в HTTP 1.0, но обязательно в HTTP 1.1:

Клиент ДОЛЖЕН включать поле заголовка Host во все сообщения запроса HTTP/1.1. Если запрошенный URI не включает имя хоста в Интернете для запрашиваемой службы, то поле заголовка Host ДОЛЖНО быть указано с пустое значение. Прокси-сервер HTTP/1.1 ДОЛЖЕН гарантировать, что любое сообщение запроса, которое он пересылает, действительно содержит соответствующее поле заголовка узла, которое идентифицирует услугу, запрошенную прокси-сервером. Все интернет-серверы HTTP/1.1 ДОЛЖНЫ отвечать кодом состояния 400 (неверный запрос) на любое сообщение запроса HTTP/1.1, в котором отсутствует поле заголовка узла.

Итак, если вы не вставляете лишнюю пустую строку, вы в конечном итоге отправляете эти запросы по отдельности:

GET /path HTTP/1.0
Host: hostname

GET /path HTTP/1.1
Host: hostname

Which are both valid.

Но когда вы вставляете дополнительную пустую строку, вы фактически отправляете два отдельных запроса одновременно:

GET /path HTTP/1.x;

Host: hostname

The request headers and request body are separated by a blank line, and a GET request does not have a request body, so the first blank line ends the request.

Таким образом, в этом случае первый запрос действителен только для HTTP 1.0 и недействителен для HTTP 1.1, поскольку заголовок Host отсутствует. Второй запрос просто недействителен в любой версии.

person Remy Lebeau    schedule 17.05.2016
comment
Спасибо, теперь это имеет больше смысла для меня. Я просто добавил несколько строк, чтобы проверить ответ сервера и извлечь новое местоположение. Он отлично работает. Очень ценю вашу помощь, я пока не могу проголосовать за это, так как у меня недостаточно репутации :( - person hvuong91; 17.05.2016