JS: DOM API
Теория: AJAX
Простые приложения в браузере, например калькулятор, могут работать сами по себе без взаимодействия с внешним миром. Все что требуется для их реализации, это написать js-код, который рисует интерфейс и обновляет DOM реагируя на события ввода чисел и клика по кнопкам.
Но такие приложения редко встречаются в реальной жизни, так как с их помощью можно решить ограниченный набор задач. Гораздо чаще, код в браузере взаимодействует с внешним миром за пределами браузера. Такие приложения состоят из двух компонентов: клиентской части (client-side) и серверной (backend), где клиент и сервер общаются друг с другом посредством HTTP-запросов. HTTP-запросы с клиентской стороны делаются с помощью механизма, который долгое время назывался Ajax, сейчас так говорят реже, но мы для простоты оставим это название. Но иногда вы будете видеть названия XHR или Fetch.
Возьмем для примера редактор Code Basics. Когда пользователь нажимает кнопку "проверить" в редакторе, то клиентский код выполняет запрос на серверную часть приложения, которая берет переданный код и запускает для него тесты. Результаты этих тестов возвращаются снова в браузер и Code Basics показывает результат выполнения этих тестов.
Все это происходит не моментально, поэтому во время проверки кнопка "проверить" блокируется и появляется спиннер. Дальше код на клиенте ждет пока придет ответ, причем предсказать время ответа невозможно. HTTP это сеть, а сеть это задержки, разрывы и плавающая скорость. Что-то может пойти не так на сервере, у клиента на машине или по пути между ними. Поэтому работа с сетью требует дополнительных усилий, особенно в области обработки ошибок.
Обратите внимание на нижнюю часть скриншота. На нем выбрана вкладка Network в DevTools. На этой вкладке отображаются все запросы к серверу, включая Ajax-запросы. Для удобства их можно отфильтровать, чтобы не мешать с другими запросами выбрав XHR/Fetch. Эта логика работает похожим образом во всех браузерах.
Попробуйте сейчас открыть в отдельной вкладке code-basics.com зайти в любой урок любого курса (регистрация не требуется) и запустить проверку, предварительно открыв вкладку Network. В конце списка вы увидите запрос на сервер. Попробуйте нажать на него и изучить.
На запрос можно нажать, тогда вы сможете увидеть более подробную информацию о нем. Какой был выполнен запрос, куда, с какими заголовками и данными. Там же есть вся информация об ответе. Если запрос вернул ошибку, то браузеры для удобства выделяют их красным цветом.
Технически HTTP-запросы из браузера делаются с помощью Fetch API представленного одной единственной функцией fetch(), которая доступна глобально. Она реализована во всех современных браузерах, поэтому ее использовать безопасно.
Fetch
fetch() асинхронная функция, которая выполняет запрос HTTP-запрос по указанному адресу с нужными заголовками и данными. Посмотрите пример вызова прямо в браузере на сайте code-basics.com:
Попробуйте скопировать эти строки и выполнить запрос в консоли браузера.
Несколько наблюдений:
- По умолчанию используется метод GET.
- Если домен не указан, то запрос идет на тот же домен, где происходит вызов, в нашем примере это https://code-basics.com.
- Данные ответа не лежат в готовом виде внутри
response, их нужно так же извлекать с помощью асинхронного вызова. Это сделано на случай использования стриминга (streaming), когда данные с сервера отдаются не сразу, а по частям.
Метод text() используется в том случае, если запрос возвращает данные не в структурированном виде, например в виде HTML. Для работы с JSON понадобится другой метод - json(). В таком случае данные сразу вернутся в виде готового объекта.
С помощью fetch() можно не только запрашивать данные, но и отправлять их на сервер. Типичный пример это отправка формы. Для этого вторым параметром в вызов fetch() передается объект, где указывается нужный метод, заголовки и данные. Для отправки данных в формате JSON, нужно добавить правильный заголовок Content-Type и выполнить преобразование данных с помощью JSON.stringify().
Полный пример отправки формы
Соберем все вместе и посмотрим на то, как можно реализовать отправку формы используя Ajax. Допустим у нас есть форма регистрации с полями для ввода имени и email:
Тогда для реализации отправки нам понадобится выполнить следующие шаги:
- Повесить асинхронный обработчик на событие "отправка формы".
- В обработчике извлечь данные формы с помощью
formData. - Выполнить отправку данных на /users/new с помощью
fetch(). - Сообщить пользователю о результатах отправки.
fetch() — это довольно низкоуровневый механизм. Например, при работе с JSON нам приходится самостоятельно выставлять заголовки и сериализовывать данные с помощью JSON.stringify(). Из-за этого широкую популярность приобрела библиотека axios, которая работает в базовом варианте практически идентично, но автоматизирует рутину.
Работа с параметрами запроса (query params)
Если ваш запрос на сервер содержит параметры запроса, то их придется добавлять в адрес запроса самостоятельно, fetch() не умеет с ними работать.
Но это не ошибка или недоработка дизайна функции. Так и было задумано, чтобы не перегружать fetch(), той функциональностью, которая уже добавлена в браузере: URL и URLSearchParams.
fetch() умеет работать с объектом URL напрямую, для этого достаточно передать его первым параметром вместо строки:
HTTP access control (CORS)
В отличие от бэкенда, HTTP-запросы на клиенте могут использоваться злоумышленниками для кражи данных. Поэтому браузеры контролируют, куда и как делаются запросы. Подробно об этом механизме можно прочитать тут



