Як працює метод HTTP GET стосовно протоколу DNS?


18

Я намагаюся зрозуміти протоколи прикладного рівня в стеку TCP / IP. Я знаю, що і HTTP, і протокол DNS залишаються на верхньому шарі (шару програми). Отже, коли браузер хоче отримати доступ до ресурсу, він повинен надіслати запит на сервер HTTP, наприклад:

GET www.pippo.it/hello.htm HTTP/1.1

Здійснюючи цей запит відповідно до правил протоколу HTTP, він використовує URL-адресу сторінки, а не IP-адресу.

Я знаю, що DNS-запит необхідний для перетворення URL-адреси в IP. Отже, моє запитання: чи HTTP викликає протокол DNS? Мені це здається неможливим, оскільки обидва є протоколами верхнього рівня (тому DNS не може надавати послугу HTTP). Так само навіть TCP (який залишається на нижчому рівні) не може попросити послугу на протоколі вищого рівня, як DNS.

Отже, коли відбувається запит DNS? А хто виконує такий запит?


1
Чи можете ви прийняти одну з відповідей, щоб уточнити, яка з цих відповідей на це питання?
030

Відповіді:


38

Запит HTTP насправді недійсний, якщо браузер не спілкується з посередником (проксі).

Ваш приклад виглядав би трохи більше, як наступний, якби браузер спілкувався безпосередньо з веб-сервером:

GET /hello.htm HTTP/1.1
Host: www.pippo.it

Тепер, щоб поставити це в перспективу, розглянемо модель OSI:

Модель OSI

У нас три системи:

  • Клієнт працює браузер
  • Веб - сервер , що обслуговує сайт
  • DNS сервер знаючи IP - адреса сайту

Запропоновані протоколи - знизу вгору (мінімальний відповідний набір для ОП):

  • IP
  • TCP, UDP
  • HTTP, DNS

Зв'язок HTTP здійснюється через протокол TCP (TCP знаходиться поверх протоколу IP), тоді як зв'язок DNS, у цьому випадку, здійснюється через протокол UDP (UDP також знаходиться поверх протоколу IP).

Ось комунікаційна послідовність коротко:

  1. Клієнт , який працює браузер, запитує сервер DNS для Aзапису на www.pippo.it, використовуючи протокол UDP.

    1.1. На клієнті саме операційна система виконує вирішальну частину і повертається до браузера --- браузер ніколи не спілкується з сервером DNS безпосередньо, а через ОС, викликаючи gethostbyname () або новіший getaddrinfo () . У Windows, порядок , в якому операційна система вирішує адреси, швидше за все , визначається що - щось на зразок цього , в той час як на Linux дозволяє старшинство визначається/etc/nsswitch.conf

  2. Сервер DNS , використовуючи протокол UDP, відповідає на клієнта записом / IP-адресою, якщо він існує

  3. Клієнт відкриває з'єднання TCP на порт 80 веб - сервера і записує наступний текст:

    HTTP-запит:

    GET /hello.htm HTTP/1.1
    Host: www.pippo.it
    

    Ви можете імітувати те саме, зробивши щось подібне у консолі чи командному рядку:

    > telnet www.pippo.it 80
    Trying 195.128.235.49...
    Connected to www.pippo.it.
    Escape character is '^]'.
    GET /hello.htm HTTP/1.1
    Host: www.pippo.it
    

    слідом за двома порожніми рядками. Якщо потрібний вміст існує, веб-сервер виведе його на екран. Якщо з іншого боку є браузер, текст відповіді переглядається браузером, і всі теги, посилання, сценарії та зображення відображаються у тому, що ми називаємо веб-сторінкою.

Насправді є ще деякі деталі, наприклад, браузери можуть кешувати IP-адреси, якщо ви вже відвідали якийсь домен, так що рішення DNS стає непотрібним. Також сучасні веб-переглядачі можуть спробувати виконати рішення, перш ніж вам це справді потрібно ( попереднє завантаження DNS ), щоб прискорити перегляд.

Крім того, ваш комп'ютер може мати статичні записи у hostsфайлі. Якщо запис відповідає запиту, локальний статичний запис спочатку використовується, і жоден DNS-сервер ніколи не зв'язується. Це налаштовується, і не обов'язково відповідає дійсності, але це стандартні налаштування в операційних системах, з якими я знайомий.


4
@trikly: саме для цього і є заголовок "Хост". Без нього у вас може бути лише один веб-сайт на IP-адресу. Це ключова різниця між HTTP / 1.0 та HTTP / 1.1. На щастя, браузери HTTP / 1.0 зараз рідкісні, але якщо ви хочете обслуговувати їх, тоді вам потрібна інша IP-адреса для кожного сайту (вони все ще можуть розміщуватися на одному сервері).
AE

1
@AE Дякую Я думаю, що мені було незрозуміло в моєму питанні, і тому Хрвойо не зрозумів, що я говорю. (Я повинен був сказати домен, а не URL). Я радий, що ти все-таки зрозумів.
trlkly

1
Ви говорите " Це неправильний запит HTTP ", і це, правда, правда, але це ближче, ніж ви маєте на увазі: " Щоб дозволити перехід до абсолютнихURI у всіх запитах у майбутніх версіях HTTP, усі сервери HTTP / 1.1 ОБОВ'ЯЗКОВО приймати форму абсолютногоURI у запити ". (RFC 2616 §5.1.2) Отже, це GET http://www.pippo.it/hello.htm HTTP/1.1було б дійсним, якщо незвичним, запитом. Це також було б дійсним і звичайним запитом на HTTP-проксі.
wfaulk

1
gethostbyname()дещо застаріла. Краще скористатись getaddrinfo()...
glglgl

1
@Utku, на жаль, ні, тому що SSH передбачає інший кінець розмовляє протокол SSH, тоді як telnet - це звичайний текстовий протокол, і його можна використовувати для спілкування з будь-яким іншим простим протоколом, наприклад, наприклад, POP3, IMAP, якщо вони не використовують SSL / TLS. потрібно було б завершити сеанс telnet таким помічником, як sslwrap або щось подібне.
Хрвой Шполяр

12

HTTP транспортується через TCP, що є протоколом IP. Щоб зробити HTTP-запит, браузер повинен відкрити TCP-з'єднання, і для цього йому потрібна IP-адреса призначення (тобто IP-адреса сервера). Для вирішення імені хоста сервера, таким чином, він повинен видати DNS-запит (зазвичай сам запит DNS надсилається операційною системою, коли програма викликає свої функції вирішення імен; однак, ніщо не заважає програмі самостійно надсилати запити DNS до DNS сервер). Після встановлення з'єднання він може надіслати свій HTTP-запит, який містить шлях до запитуваного ресурсу, і поле Хоста з іменем хоста сервера (наприклад, Host: www.pippo.it). Ім'я хоста не входить у рядок запиту (це було б насправдіGET /hello.htm HTTP/1.1), за винятком випадків, коли запит надсилається до HTTP-проксі (і в цьому випадку присутня повна URL-адреса, включаючи частину протоколу, наприклад GET http://www.pippo.it/hello.htm HTTP/1.1),


Дякую, зараз це зрозуміліше, але не повністю. Ви пишете, що браузер повинен видавати запит DNS. Гаразд, але після отримання IP-адреси від сервера DNS, як це використовувати? Тобто, такий IP не відображається в HTTP-запиті. Тому я припускаю, що перед тим, як надсилати HTTP-запит, є ще один крок, і я думаю, що це відкриття з'єднання. Цей пункт мені не дуже зрозумілий ... Ще раз дякую!
Джанкарло Перло

5
Дійсно, IP необхідний для відкриття TCP-з'єднання, всередині якого транспортується HTTP-запит. Власне, IP-адреса як клієнта, так і сервера надсилається разом із ВСІМ пакетами з'єднання. Найкращий спосіб дізнатися, як це працює, - це, мабуть, встановити інструмент захоплення пакетів (Wireshark - це відмінна мультиплатформна платформа з відкритим кодом), захопити простий HTTP-запит, відфільтрувати його з решти мережевої активності та подивитися, як всі пакети були відправлені на дріт. Фактично ви повинні мати можливість бачити запит DNS і перед з'єднанням TCP.
Але

1
Проксі-запити повинні використовувати заголовок хоста, не вводячи повну URL-адресу в рядок GET.
OrangeDog

1
@OrangeDog: Ні, навпаки. RFC 7230 (розділ 5.3.2) прямо говорить, що клієнт, який робить запит на проксі, ОБОВ'ЯЗКОВО повинен використовувати абсолютний URI у рядку запиту. (Там повинні ще бути заголовок вузла дублюючи інформацію з рядка запиту, розділ 5.4).
hmakholm залишився над Монікою

8

Процедура йде так:

  1. Користувач (ви) надає веб-переглядачу URL, наприклад http://www.pippo.it/hello.htm
  2. Браузер розділяє це на три частини:

    • Протокол http
    • Ім'я хоста www.pippo.it
    • URL-шлях /hello.htm

    (Більш складна URL-адреса може мати і інші частини, я зараз ігнорую цю можливість)

  3. Браузер знає, що для створення IP-з'єднання йому потрібна IP-адреса. Щоб отримати IP-адресу, йому потрібно використовувати DNS (якщо вона не має кешовану адресу).

    1. Браузер запитує в операційній системі IP-адресу сервера DNS; припустимо, це отримує 8.8.8.8.
    2. Браузер будує таке багатошарове з'єднання:

      • IP-рівень: підключіться до 8.8.8.8
      • Рівень UDP: встановити пакет для порту призначення 53
      • DNS-рівень: створити запит DNS для Aзапису для імені хостаwww.pippo.it

      Звичайно, я опускаю багато деталей щодо, наприклад, точного формату пакетів.

    3. Браузер отримує відповідь DNS (шаруватий поверх UDP, шаруватий поверх IP тощо), який дає IP-адресу для www.pippo.it, скажімо, це10.11.12.13
  4. Браузер знає, що для створення TCP-з'єднання йому потрібен номер порту. Щоб отримати номер порту, він шукає протокол httpу своїй внутрішній таблиці і дізнається, що він повинен використовувати порт 80.
  5. Браузер будує таке багатошарове з'єднання:

    • IP-рівень: підключіться до 10.11.12.13
    • TCP-шар: встановлення пакетів на порт 80 призначення
    • Рівень HTTP: створіть HTTP-запит для URL-адреси /hello.htmна хості www.pippo.it(оскільки на комп'ютері 10.11.12.13може розміщуватися кілька доменів, тому він повинен знати, який з них бажано)

      GET /hello.htm HTTP/1.1
      Host: www.pippo.it
      ...
      

    Звичайно, я опускаю всі деталі рукостискання TCP і таке інше.

  6. Веб-переглядач отримує відповідь HTTP (шаруватий поверх TCP, шаруватий поверх IP та ін.), Що містить вміст hello.htm

І на користь, я зазначу, що браузер зараз вивчає вміст цієї відповіді та визначає необхідні додаткові ресурси: зображення, CSS, Javascript тощо. Потім він повторює весь цей процес для кожного такого ресурсу.


4
Крок 3 насправді - це не те, що робить сама програма. Додаток просто використовує щось на кшталт getaddrinfoабо gethostbynameпросить ОС вирішити адресу для нього. Також ОС зазвичай використовує кілька механізмів, щоб намагатися шукати імена, не тільки DNS. (Як правило, принаймні файл хостів крім DNS.)
Håkan Lindqvist

Спасибі! Це дійсно вражаюча і детальна відповідь і дуже корисна!
Джанкарло Перло

Це найкраща відповідь.
Сінь
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.