Что случилось с этим перенаправлением 302 на тот же URL-адрес?


Я просматривал свой веб-сайт в поисках ссылок, указывающих на перенаправление HTTP 301/302/303, когда обнаружил загадочное поведение утилиты curl. Рассмотрим выходные данные следующих трех команд:

$ curl -I http://jekyllrb.com
HTTP/1.1 302 Found
Connection: close
Pragma: no-cache
cache-control: no-cache
Location: /

$ curl -I http://jekyllrb.com/
HTTP/1.1 302 Found
Connection: close
Pragma: no-cache
cache-control: no-cache
Location: /

$ curl -LI http://jekyllrb.com/
HTTP/1.1 200 OK
Server: GitHub.com
Date: Tue, 30 Dec 2014 01:31:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 8177
Last-Modified: Mon, 22 Dec 2014 14:17:25 GMT
Expires: Tue, 30 Dec 2014 01:41:47 GMT
Cache-Control: max-age=600
Vary: Accept-Encoding
Accept-Ranges: bytes

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

Затем, когда вы добавляете -L возможность указать curl следовать перенаправлениям, это выглядит так, как будто вы переходите непосредственно на реальную страницу без каких-либо промежуточных шагов! (Обычно, когда curl следует перенаправлениям, он печатает набор заголовков для каждого запроса - если бы где-то там был HTTP 302, то он должен был быть показан до HTTP 200.)

Может ли кто-нибудь объяснить мне (1), почему перенаправление на один и тот же URL-адрес допустимо; и (2) почему включение флага -L, похоже, не следует, а вместо этого полностью обходит перенаправление?

Author: unor, 2014-12-30

2 answers

Ваши первые два запроса одинаковы. Все клиенты (включая curl) должны отправлять косую черту после имени домена как часть HTTP-запроса, независимо от того, находится ли он в URL-адресе. Без него невозможно сформулировать действительный HTTP-запрос. Минимальный HTTP-запрос:

GET / HTTP/1.0
host: jekyllrb.com

Пропуск косой черты из этого приведет к ошибке "400 неверных запросов".

Похоже, что поведение является прерывистым. Иногда сервер отвечает перенаправлением, а иногда нет. Я сам пробовал это десятки раз с помощью curl и иногда получаю перенаправление, но в большинстве случаев этого не происходит.

Перенаправление на один и тот же URL-адрес иногда используется для установки файлов cookie и проверки их установки. Я не вижу, чтобы в этом запросе были установлены какие-либо файлы cookie, но curl может повторить запрос, который перенаправляет на тот же URL-адрес с опцией -L.

 5
Author: Stephen Ostermiller, 2014-12-30 03:18:05

Вау, это действительно странно.

Как упоминалось в другом ответе, конечная косая черта после имени домена всегда обязательна в HTTP-запросах, поэтому не ожидается, что вы получите перенаправление, если попытаетесь получить доступ к домену "без" какого-либо определенного пути.

Я попробовал ваш домен как curl -v http://jekyllrb.com, и действительно, только с третьей попытки я действительно получил 200 OK и содержимое страницы, вместо этого получив 302 Found по предыдущим двум запросам.


  • Мой предположим, что выполнение нескольких перенаправлений на себя является простым для клиентов со стандартным поведением, но может быть проблематичным для некоторых сломанных ботов, и GitHub может использовать его как метод, чтобы избежать некоторых сборщиков электронной почты или чего-то подобного? Возможно, аналогично по концепции серому списку в SMTP?

  • Еще одним потенциальным преимуществом, о котором я мог бы подумать, может быть скорость выполнения отдельных запросов - возможно, у него нет содержимого страницы заранее, поэтому он перенаправляет на вместо этого, гарантируя, что каждый отдельный запрос выполняется очень быстро.

  • Или, возможно, это делается для минимизации использования пропускной способности, предоставляя перенаправление клиентам, не являющимся браузерами, которые, возможно, не потрудятся сделать второй запрос? Просто еще одна отдаленная догадка.


Cns:cnst {8395} curl -v http://jekyllrb.com; date
* About to connect() to jekyllrb.com port 80 (#0)
*   Trying 192.30.252.153...
* connected
* Connected to jekyllrb.com (192.30.252.153) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.26.0
> Host: jekyllrb.com
> Accept: */*
>
< HTTP/1.1 302 Found
< Connection: close
< Pragma: no-cache
< cache-control: no-cache
< Location: /
<
* Closing connection #0
Tue Dec 30 10:57:35 PST 2014
Cns:cnst {8396} curl -v http://jekyllrb.com ; date
* About to connect() to jekyllrb.com port 80 (#0)
*   Trying 192.30.252.153...
* connected
* Connected to jekyllrb.com (192.30.252.153) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.26.0
> Host: jekyllrb.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: GitHub.com
< Date: Tue, 30 Dec 2014 18:57:36 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 8177
< Last-Modified: Mon, 22 Dec 2014 14:17:25 GMT
< Expires: Tue, 30 Dec 2014 19:07:36 GMT
< Cache-Control: max-age=600
< Accept-Ranges: bytes
<
<!DOCTYPE HTML>
<html lang="en-US">
<head>
  <meta charset="UTF-8">
  <title>Jekyll &bull; Simple, blog-aware, static sites</title>
 3
Author: cnst, 2014-12-30 19:08:50