
Localhost - это имя, которым ваш компьютер называет сам себя. Наберите его в браузере, и запрос никогда не дойдёт до сети: он выйдет из браузера, развернётся внутри машины и через несколько микросекунд придёт к тому, что слушает этот порт.
Вот и всё определение, и оно действительно простое. Непростое в том, что браузер намеренно обращается с этим адресом иначе, чем со всеми остальными, и сразу по нескольким пунктам. Поэтому страница, отданная с localhost, - это не та же самая страница, отданная с домена, а в зазорах между ними живёт особый сорт багов: тот, что невидим ровно до момента выкатки.
localhost, 127.0.0.1 и третье, о котором никто не упоминает
Их используют как синонимы, и это не одно и то же.
- 127.0.0.1
- Адрес. Петлевой адрес IPv4, жёстко означающий "эта машина". Никакого разрешения имён
- ::1
- Та же идея в IPv6 и другой адрес. Сервер, привязанный только к IPv4, здесь не слушает
- localhost
- Имя, которое разрешается в один из двух. Обычно в оба, и порядок выбирает машина
- 0.0.0.0
- Не адрес, по которому ходят. Это значит "слушай на всех интерфейсах", и именно это делает сервер доступным с телефона в той же сети
Третья строка - источник одного вполне определённого изматывающего дня. localhost - это имя
хоста, и машина его разрешает. В системе, предпочитающей IPv6, localhost превращается в ::1, а
сервер, привязанный только к 127.0.0.1, на ::1 не слушает. В итоге на localhost соединение
отклоняется, а на 127.0.0.1 страница прекрасно работает, и это читается так, будто машина
противоречит сама себе. Не противоречит. Это два адреса, и ваш сервер на одном из них.
Почему браузер здесь гнёт собственные правила
Это та часть, которая важна для багов, и большинство объяснений про localhost её вовсе опускает.
Браузеры требуют безопасного контекста для длинного списка возможностей: service worker, API буфера обмена, геолокация, камера и микрофон, уведомления и не только. Безопасный контекст обычно означает HTTPS. Но localhost считается потенциально заслуживающим доверия и получает исключение, потому что трафик никогда не покидает машину и между ними нет ничего, что могло бы его перехватить.
Рассуждение здравое, а последствие - ловушка. Всё из этого списка работает на http://localhost и
перестаёт работать в тот момент, когда тот же код отдаётся с http://ваш-стейджинг по обычному
HTTP. Ничто в вашем локальном запуске не сказало вам, что функция зависит от безопасного контекста,
потому что для вас правило локально отменили, а везде остальное применяют.
Остальные различия, и все они указывают в одну сторону
Localhost - это не уменьшенный продакшен. Это другая среда, в которой по случайности выполняется тот же код, и почти каждое отличие вам льстит.
Сети нет. Ни задержек, ни потерь пакетов, ни шаткого вайфая. Любая гонка, зависящая от того, что один запрос придёт после другого, локально разрешается быстрым путём, а у человека в поезде - другим. Индикаторы загрузки, которых никто никогда не видит, обычно про это.
Нет CDN, нет прокси, нет балансировщика. Сжатие, кеширование, переписывание заголовков и буферизация запросов, стоящие перед продакшеном, отсутствуют целиком. Ответ, работающий локально, может быть преобразован чем-то посередине, прежде чем его увидит настоящий пользователь.
Файловая система, скорее всего, не различает регистр. На macOS и Windows Logo.svg и
logo.svg - один файл. На Linux-машине, куда вы выкатываетесь, - нет, и импорт, работавший на
компьютере каждого разработчика, в продакшене даёт 404.
Куки ведут себя иначе. Браузеры обрабатывают localhost особым образом для безопасных куки, и
у него нет регистрируемого домена, так что SameSite и поведение между поддоменами, которое вы
локально не задействуете никогда, в продакшене задействуется сразу.
Вы - один пользователь. Никакой параллельности, никакого пула соединений под нагрузкой, никакого кеша, который уже прогрел другой запрос.
Каждое из этого делает локальный запуск легче настоящего. Вот та закономерность, которую стоит заметить: localhost падает не иначе, он падает реже, и именно это превращает “у меня на localhost работает” в слабый сигнал, а не в успокоение.
Что эта фраза на самом деле означает
Когда кто-то говорит, что локально работает, а в продакшене нет, он не сделал утверждения о коде. Он сделал утверждение о двух средах, и полезный вопрос - какое именно различие виновато.
Список короткий, и он каждый раз один и тот же: исключение для безопасного контекста, отсутствие сети, отсутствие промежуточных узлов, регистр в именах файлов, область видимости куки и нагрузка. Баг, появляющийся при выкатке и не появляющийся локально, почти всегда один из этих шести, и знание их превращает “на моей машине работает” из обвинения в чек-лист.
Это же и причина, по которой существует стейджинг, и по которой он тоже никогда не бывает точной копией.
Как выяснить, какое именно
Трудность бага среды в том, что его не видно из той среды, в которой находитесь вы. Человек, столкнувшийся с ним, находится по другую сторону, со страницей, которая не работает, и без возможности объяснить вам почему, а ваша машина продолжает настаивать, что всё в порядке.
Session Replay
Бесплатное расширение Chrome. Один клик на странице, которая ведёт себя неправильно, захватывает снимок экрана, консоль и сетевой журнал, и даёт вам ссылку для вставки в задачу.
Консоль - это место, где о себе заявляет сбой безопасного контекста, а сетевой журнал - место, где всплывают и переписывание прокси, и 404 на файл, который локально есть, и куки, которые так и не отправили. Захваченные на той машине, где всё действительно сломалось, эти двое отвечают на вопрос, на который ваша собственная машина ответить не может.
В одном абзаце
Localhost - это имя, которым ваш компьютер называет сам себя, разрешающееся в 127.0.0.1 или
::1, и сервер, привязанный к одному из них, не слушает на другом, - в этом всё объяснение того,
почему localhost отклоняет соединение, которое принимает 127.0.0.1. Важнее другое: браузеры
считают его безопасным контекстом даже по обычному HTTP, поэтому service worker, буфер обмена,
геолокация и камера работают локально и могут перестать работать в тот момент, когда тот же код
начнут отдавать по HTTP откуда-то ещё. Прибавьте отсутствующую сеть, отсутствующие прокси и CDN,
файловую систему без различения регистра, другую область видимости куки и нагрузку ровно в единицу,
и localhost окажется не маленьким продакшеном, а средой, которая падает реже, - поэтому “у меня на
localhost работает” само по себе ничего не сужает.