Коли веб-сервери надсилають сторінку, чому вони не надсилають усі необхідні CSS, JS та зображення, не запитуючи їх?


45

Якщо веб-сторінка містить один файл CSS та зображення, чому браузери та сервери витрачають час на цей традиційний трудомісткий маршрут:

  1. браузер надсилає початковий GET-запит на веб-сторінку і чекає відповіді сервера.
  2. браузер надсилає ще один GET-запит на файл css і чекає відповіді сервера.
  3. браузер надсилає ще один GET-запит на файл зображення та чекає відповіді сервера.

Коли ж замість цього вони могли використовувати цей короткий, прямий, економію часу маршрут?

  1. Браузер надсилає GET-запит на веб-сторінку.
  2. Веб-сервер відповідає за допомогою ( index.html, а потім style.css та image.jpg )

2
Будь-який запит не може бути зроблений, поки веб-сторінка, звичайно, не буде отримана. Після цього запити робляться в порядку, коли читається HTML. Але це не означає, що одночасно робиться лише один запит. Насправді робиться кілька запитів, але іноді існують залежності між запитами, і деякі мають бути вирішені, перш ніж сторінку можна буде належним чином намалювати. Браузери іноді роблять паузу, оскільки запит задовольняють, перш ніж з'являтися для обробки інших відповідей. Реальність перебуває більше на стороні браузера, оскільки вони, як правило, вимагають великих ресурсів.
closetnoc

20
Я здивований, ніхто не згадував кешування. Якщо у мене вже є цей файл, він мені не потрібен, він надсилається мені.
Корі Огберн

2
У цьому списку може бути сотні речей. Хоча коротше, ніж насправді надсилання файлів, це все ще далеко не оптимальне рішення.
Корі Огберн

1
Насправді я ніколи не відвідував веб-сторінку, яка містить понад 100 унікальних ресурсів ..
Ахмед

2
@AhmedElsoobky: браузер не знає, які ресурси можна надіслати як заголовок кешованих ресурсів, не попередньо завантажуючи саму сторінку. Також це було б кошмаром конфіденційності та безпеки, якщо отримання сторінки скаже серверу, що у мене є інша кешована сторінка, яка, можливо, контролюється іншою організацією, ніж оригінальна сторінка (веб-сайт, який має багато орендарів).
Лі Лі Райан

Відповіді:


63

Коротка відповідь - "Тому що HTTP не був призначений для цього".

Тім Бернерс-Лі не розробив ефективний та розширюваний мережевий протокол. Його єдиною метою дизайну була простота. (Професор мого мережевого класу в коледжі сказав, що він повинен був залишити роботу професіоналам.) Проблема, яку ви окреслили, є лише однією з багатьох проблем з протоколом HTTP. У первісному вигляді:

  • Не було версії протоколу, просто запит на ресурс
  • Заголовків не було
  • Кожен запит вимагав нового TCP-з'єднання
  • Не було стиснення

Пізніше протокол було переглянуто для вирішення багатьох із цих проблем:

  • Прохання були розроблені, тепер запити виглядають так GET /foo.html HTTP/1.1
  • Додані заголовки для метаінформації як із запитом, так і з відповіддю
  • З’єднання було дозволено повторно використовувати Connection: keep-alive
  • Складені відповіді були введені, щоб дозволити повторно використовувати з'єднання, навіть коли розмір документа не відомий достроково.
  • Додано стиснення Gzip

На даний момент HTTP було розроблено наскільки це можливо, не порушуючи зворотної сумісності.

Ви не перша особа, яка запропонувала клієнту перенести сторінку та всі її ресурси. Насправді Google розробила протокол, який може робити так званий SPDY .

Сьогодні і Chrome, і Firefox можуть використовувати SPDY замість HTTP для серверів, які його підтримують. Основними функціями порівняно з HTTP на веб-сайті SPDY є:

  • SPDY дозволяє клієнту та серверу стискати заголовки запитів і відповідей, що зменшує використання пропускної здатності, коли подібні заголовки (наприклад, файли cookie) надсилаються знову і знову для декількох запитів.
  • SPDY дозволяє декілька одночасно мультиплексованих запитів через одне з'єднання, економлячи на зворотних поїздках між клієнтом і сервером і запобігаючи блокуванню запитів з більш високим пріоритетом ресурсів з низьким пріоритетом.
  • SPDY дозволяє серверу активно підштовхувати ресурси до клієнта, який він знає, що клієнту знадобляться (наприклад, файли JavaScript та CSS), не чекаючи, коли клієнт вимагатиме їх, дозволяючи серверу ефективно використовувати невикористану пропускну здатність.

Якщо ви хочете обслуговувати свій веб-сайт із SPDY у браузерах, які його підтримують, ви можете це зробити. Наприклад, Apache має mod_spdy .

SPDY став основою для HTTP версії 2 із технологією push push сервера.


2
Добре і поінформована відповідь! Веб-браузери за своєю суттю є послідовними, і запити можуть бути зроблені досить швидко. Один погляд на файл журналу покаже, що запити на ресурси надсилаються досить швидко після розбору HTML. Це те, що воно є. Непогана система, просто не настільки ефективна, як код / ​​ресурс.
closetnoc

6
Тільки для запису, SPDY - це не святий грааль. Деякі речі це добре, але вводить інші проблеми. Ось одна стаття, що містить деякі моменти, що говорять про те, що SPDY.
Джост

3
Я настійно рекомендую всім, хто цікавиться цим, прочитати критику за посиланням @Jost. Це дає вам натяк на складність, яка полягає у з'ясуванні того, як зробити дуже часто реалізовану річ не просто поступово краще, а набагато краще, щоб усі почали її використовувати . Легко подумати про вдосконалення, що робить щось дещо кращим для порівняно великого набору випадків використання. Щоб покращити справи таким чином, щоб усі почали використовувати ваш новий протокол, оскільки це настільки краще, що варто змінити вартість - це зовсім інша справа, і це зробити непросто.
msouth

11
він мав би залишити роботу професіоналам : якби він це зробив, їм знадобилося б шість років, щоб придумати стандарт, який був би застарілим у день виходу, і незабаром з’явиться десяток конкуруючих стандартів. Крім того, чи потрібен був професіонал від когось дозволу? Чому вони цього не зробили самі?
Шантну Тіварі

2
Якщо чесно, то кваліфікованих фахівців тоді ще не було. Ніхто не знає, як побудувати всесвітню павутину, бо її ніхто ніколи не будував. Поняття гіпермедіа Тим не винайшов, він мав досвід роботи з різними локальними системами гіпермедіа за десять років до того, як написав пропозицію про "Управління інформацією" для вирішення проблеми "втрати інформації" в ЦЕРН.
Лі Лі Райан

14

Ваш веб-браузер не знає про додаткові ресурси, поки не завантажить веб-сторінку (HTML) з сервера, яка містить посилання на ці ресурси.

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

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

Отже, коли веб-браузер отримує веб-сторінку з сервера, він перевіряє, які пов’язані ресурси у нього НЕ є в кеші, а потім робить додаткові запити HTTP для цих ресурсів. Досить простий, дуже гнучкий і розширюваний.

Веб-браузер зазвичай може робити два HTTP-запити паралельно. Це не відрізняється від AJAX - вони є асинхронними методами завантаження веб-сторінок - асинхронним завантаженням файлів та асинхронним завантаженням вмісту. За умови збереження життя ми можемо зробити декілька запитів, використовуючи одне з'єднання, а за допомогою конвеєра ми можемо зробити кілька запитів, не чекаючи відповідей. Обидві ці методи дуже швидкі, оскільки більшість накладних витрат зазвичай надходить із відкриття / закриття TCP-з'єднань:

підтримувати

трубопровідні

Трохи історії веб-сторінки ...

Веб-сторінки починалися як звичайний текстовий електронний лист, і комп'ютерна система розроблялася навколо цієї ідеї, утворюючи дещо безкоштовну для всіх платформу зв'язку; веб-сервери в той час ще були власником. Пізніше до "специфікації електронної пошти" було додано більше шарів у вигляді додаткових типів MIME, таких як зображення, стилі, сценарії тощо. Зрештою, MIME означає багатоцільове розширення Інтернет- пошти . Рано чи пізно у нас з’явилося те, що по суті є мультимедійним електронним повідомленням, стандартизованими веб-серверами та веб-сторінками.

HTTP вимагає, щоб дані передавались у контексті електронних повідомлень, схожих на електронну пошту, хоча дані найчастіше насправді не є електронною поштою.

По мірі розвитку такої технології, вона повинна дозволяти розробникам поступово включати нові функції, не порушуючи існуючого програмного забезпечення. Наприклад, коли в специфікацію додається новий тип MIME - скажімо JPEG - веб-серверам та веб-браузерам знадобиться певний час, щоб це здійснити. Ви не просто раптом змушуєте JPEG в специфікації і починаєте надсилати його у всі веб-браузери, ви дозволяєте веб-браузеру запитувати підтримувані ним ресурси, що робить усіх щасливими, а технологія рухається вперед. Чи потрібен екранному зчитувачу всі JPEG на веб-сторінці? Напевно, ні. Якщо ви змушені завантажувати купу файлів Javascript, якщо ваш пристрій не підтримує Javascript? Напевно, ні. Чи потрібно Googlebot завантажувати всі ваші файли Javascript, щоб правильно індексувати ваш сайт? Ні.

Джерело: Я розробив веб-сервер на основі подій, як Node.js. Це називається Rapid Server .

Список літератури:

Подальше читання:


Ну, насправді, ми можемо подбати про всі ті побічні проблеми (такі як: Кеш, Заголовок типу вмісту ... і т.д.), для вирішення цих проблем існують обхідні шляхи . І як я запропонував у коментарях до публікації вище, ми можемо використовувати щось подібне до цього заголовка> Cached-Resources: image.jpg; style.css; щоб вирішити проблему кешування .. (Якщо у вас є час, то можете поглянути на коментарі вище).
Ахмед

Так, ця ідея раніше передавалася моїй думці, але це просто занадто великі витрати на HTTP, і це не вирішує того факту, що ресурси можуть бути розповсюджені на декількох серверах. Крім того, я не думаю, що запропонований вами метод економії часу насправді заощадить час, оскільки дані будуть надсилатися як потік незалежно від того, як ви їх переглядаєте, а з підтримкою роботи 100 одночасних HTTP-запитів фактично стає 1 запитом. Технологія та можливості, які ви пропонуєте, схоже, вже існують певним чином. Дивіться en.wikipedia.org/wiki/HTTP_persistent_connection
perry

@perry: Що б ви думали про ідею альтернативи https://надсиланню великих публічно розповсюджених файлів, які потрібно автентифікувати, але не залишатись конфіденційними: включіть у URL-адресу хеш певних частин заголовка законної відповіді, що може, у свою чергу, включити або підпис, або хеш корисної навантаження даних, і чи переглядають веб-переглядачі перевірку отриманих даних щодо заголовка? Така конструкція не тільки заощадить деякі кроки рукостискання з SSL, але ще важливіше дозволить кешувати проксі. Отримайте URL-адресу за посиланням SSL, і дані можуть надходити з будь-якого місця.
supercat

11

Бо вони не знають, що це за ресурси. Активи, потрібні веб-сторінці, кодуються в HTML. Тільки після того, як аналізатор визначить, що це за активи, може бути запитаний користувачем-агентом.

Крім того, як тільки ці активи відомі, їх потрібно обслуговувати індивідуально, щоб відповідні заголовки (тобто тип контенту) могли подаватись, щоб користувальницький агент знав, як з ним поводитися.


2
Особливо, якщо ви використовуєте щось на зразок Requ.js. Браузер запитує лише те, що йому потрібно. Уявіть, що вам доведеться завантажувати все одразу ...
Аран Малхолланд

2
Це правильна відповідь, і одна, якої, здається, більшість коментаторів не вистачає - для того, щоб сервер активно активував надсилання ресурсів, він повинен знати, що вони є, а це означає, що сервер повинен був би розібрати HTML.

1
Але питання задає питання, чому веб- сервер не надсилає ресурси, а не тому, чому клієнт не може запитувати їх одночасно. Дуже легко уявити світ, у якому сервери мають пакет пов'язаних активів, які всі надсилаються разом, який не розраховує на аналіз HTML для створення пакету.
Девід Мейстер

@DavidMeister Оскільки сервер не завжди знає, що хоче клієнт - веб-сканер для пошукової системи може не піклуватися про CSS / JS, а в документі є багато інших ресурсів, пов'язаних із ними, окрім цих - не потрібно надсилати весь RSS подається в пакеті до веб-браузера (більша частина вмісту, ймовірно, вже в HTML), тоді як читач каналів може просто розібрати <head>елемент, шукаючи альтернативні посилання RSS, щоб знайти саме це - клієнт може надіслати список що це цікавить, але тоді йому потрібно знати, що є, і ми знову на початку
Джаф - Бен Дюгід

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

8

Тому що у вашому прикладі веб-сервер завжди надсилатиме CSS та зображення незалежно від того, чи є у клієнта їх, тим самим сильно витрачаючи пропускну здатність (і тим самим роблячи з'єднання повільнішим , а не швидшим, зменшуючи затримку, що, імовірно, було вашим наміром). Зауважте, що файли CSS, JavaScript та зображень зазвичай надсилаються із дуже тривалим терміном дії саме з цієї причини (як коли потрібно змінити їх, ви просто зміните ім'я файлу, щоб примусити нову копію, яка знову буде кешована довгий час).

Тепер ви можете спробувати обійти цю втрату пропускної здатності, сказавши " Гаразд, але клієнт міг вказати, що у нього вже є деякі з цих ресурсів, тому сервер не надсилатиме його знову ". Щось на зразок:

GET /index.html HTTP/1.1
Host: www.example.com
If-None-Match: "686897696a7c876b7e"
Connection: Keep-Alive

GET /style.css HTTP/1.1
Host: www.example.com
If-None-Match: "70b26618ce2c246c71"

GET /image.png HTTP/1.1
Host: www.example.com
If-None-Match: "16d5b7c2e50e571a46"

А потім отримуйте лише ті файли, які не змінилися, надсилаєтесь через одне з'єднання TCP (використовуючи HTTP-конвеєрне з'єднання через постійне з'єднання). І вгадайте, що? Так воно вже працює (ви також можете використовувати If-Modified-Since замість If-None-Match ).


Але якщо ви дійсно хочете зменшити затримку, витрачаючи велику пропускну здатність (як у вашому початковому запиті), ви можете зробити це сьогодні, використовуючи стандартний HTTP / 1.1 при розробці вашого веб-сайту. Причина, що більшість людей цього не робить, це тому, що вони не вважають, що цього варто.

Для цього вам не потрібно мати CSS або JavaScript в окремому файлі, ви можете включити їх в основний HTML-файл за допомогою <style>та <script>тегів (вам, мабуть, навіть не потрібно це робити вручну; ваш механізм шаблонів, ймовірно, може робити це автоматично) . Ви навіть можете включити зображення у файл HTML за допомогою URI даних , наприклад:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

Звичайно, кодування base64 трохи збільшує використання пропускної здатності, але якщо ви не піклуєтесь про витрачену пропускну здатність, це не повинно бути проблемою.

Тепер, якщо ви дійсно піклуєтесь, ви навіть можете зробити вас веб-скриптами досить розумними, щоб отримати найкращі можливості з обох світів: за першим запитом (у користувача немає файлу cookie), надішліть все (CSS, JavaScript, зображення), вбудовані просто в один єдиний HTML файл, як описано вище, додайте посилання rel = "prefetch" теги для зовнішніх копій файлів та додайте cookie. Якщо користувач вже має печиво (наприклад, він відвідав раніше), а потім відправити його просто звичайний HTML з <img src="example.jpg">, і <link rel="stylesheet" type="text/css" href="style.css">так далі

Тож при першому відвідуванні браузер запитав би лише один HTML-файл і отримав і покаже все. Тоді воно (при простої) попередньо завантажує вказані зовнішні CSS, JS, зображення. Наступного разу, коли користувач відвідує, браузер запитає та отримує лише змінені ресурси (можливо, лише новий HTML).

Додаткові дані CSS + JS + зображень надсилатимуться лише двічі, навіть якщо ви сотні разів клацнули на веб-сайті. Набагато краще, ніж у сотні разів, як пропонувало ваше запропоноване рішення. І ніколи (ні в перший раз, ні в наступний раз) не використовувати більше, ніж один зворотній шлях, що збільшує затримку.

Тепер, якщо це звучить як занадто багато роботи, і ви не хочете йти з іншим протоколом, як SPDY , вже є модулі типу mod_pagespeed для Apache, які можуть автоматично виконати частину цієї роботи для вас (об'єднання декількох файлів CSS / JS в один, автоматично вставляючи невеликий CSS і мінімізуючи їх, зробіть маленькі зображення, заповнені заповнювачем, під час очікування завантаження оригіналів, ледачих завантажень зображень тощо), не вимагаючи зміни одного рядка веб-сторінки.


3
Я думаю , що це правильна відповідь.
el.pescado

7

HTTP2 заснований на SPDY і робить саме те, що ви пропонуєте:

На високому рівні HTTP / 2:

  • є двійковим, а не текстовим
  • є повністю мультиплексованим, замість впорядкованого та блокувального
  • тому можна використовувати одне з'єднання для паралелізму
  • використовує стиснення заголовка для зменшення накладних витрат
  • дозволяє серверам активно "проштовхувати" відповіді в кеші клієнтів

Більше доступно на HTTP 2 Faq


3

Тому що не передбачається, що ці речі справді потрібні .

Протокол не визначає будь-яких спеціальних обробок для будь-якого конкретного типу файлу або користувача-агента. Він не знає різниці між, скажімо, файлом HTML і зображенням PNG. Для того, щоб робити те, що ви просите, веб-сервер повинен був би визначити тип файлу, проаналізувати його, щоб з’ясувати, які інші файли він посилається, а потім визначити, які саме файли потрібні насправді, враховуючи, що ви маєте намір робити файл . З цим є три великі проблеми.

Перша проблема полягає в тому, що не існує стандартного надійного способу ідентифікації типів файлів на кінці сервера . HTTP управляє за допомогою механізму Content-Type, але це не допомагає серверу, який повинен розібратися в цьому матеріалі самостійно (почасти так, щоб він знав, що вкласти у Content-Type). Розширення імен файлів широко підтримуються, але крихкі та легко обдурені, іноді для шкідливих цілей. Метадані файлової системи менш крихкі, але більшість систем підтримують її не дуже добре, тому сервери навіть не турбуються. Нюхання вмісту (як fileнамагаються зробити деякі браузери та команда Unix ) може бути надійним, якщо ви готові зробити його дорогим, але надійне нюхання занадто дороге, щоб бути практичним на сервері, а дешеве нюхання недостатньо надійне.

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

Третя проблема полягає в тому, що сервер не може знати, що ви маєте намір робити з файлом . Веб-переглядачу можуть знадобитися файли, на які посилається HTML, але він може не бути, залежно від конкретного контексту, в якому виконується файл. Це було б досить складно, але в Інтернеті є більше, ніж просто веб-переглядачі: між павуками, агрегаторами каналів та зчитуванням сторінок, є багато видів користувальницьких агентів, які не потребують файлів, на які посилається HTML-код : вони дбайте лише про сам HTML. Надсилання цих інших файлів таким агентам користувача лише втратить пропускну здатність.

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


Якщо ми збираємось розробити новий протокол або виправити вже існуючий, ми можемо подбати про всі ці проблеми так чи інакше! І веб-сервер буде аналізувати файли лише один раз, а потім може класифікувати їх залежно від визначених правил, щоб він міг визначити пріоритет, які файли надсилати спочатку..etc, а веб-сервер не повинен знати, що я маю робити з тими файлами, він просто повинен знати, що надсилати, коли це робити і залежно від того, які правила .. (веб-боти та павуки - це не проблема, поведінка з ними буде відрізнятися - у них є унікальні заголовки користувачів-агента- ..)
Ахмед

@AhmedElsobky: Те, про що ви говорите, більше схоже на конкретну реалізацію, ніж мережевий протокол. Але дійсно потрібно знати, що ви маєте намір робити з файлами, перш ніж він зможе визначити, що надсилати: інакше він неминуче надсилатиме файли, які багато користувачів не хочуть. Ви не можете довіряти рядкам User-Agent, тому не можете використовувати їх для визначення того, що призначений для користувача.
Найспокійніший
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.