Руководство для начинающих по HTTP. Часть 3. Запросы

Руководство для начинающих по HTTP. Часть 3. Запросы

27 марта 2022 г.

В этой части серии я продемонстрирую создание HTTP-запросов из простого приложения React с использованием XHR, Fetch и Axios. Вы можете просмотреть весь код в [репозитории Github] (https://github.com/abbeyperini/HTTP101). После этого в «Руководстве по HTTP для начинающих — Часть 4: API» мы немного повеселимся с API, созданными другими людьми.


Я рассмотрел термины и определения, необходимые для понимания HTTP-сообщений, в [части 1] (https://app.hackernoon.com/mobile/zMMaTOpLCUcCQs4ntqPT). Затем я продемонстрировал, как генерировать ответные сообщения в часть 2. Итак, мы знаем, что перед отправкой сообщения запроса с инструкциями для сервера клиент должен его закодировать и прикрепить информацию, которая потребуется серверу для ее декодирования. Затем, после того как клиент получит ответ от сервера, его также необходимо будет расшифровать. Давайте погрузимся в код, необходимый для всего этого.


Введение и оглавление


В этой статье предполагается, что вы знакомы с основами JavaScript, командной строкой и терминами, определенными в части 1. Также предполагается, что вы следили за [частью 2] (https://app.hackernoon.com/mobile/URwef1IC4FutwiOmJmPM).


  1. [Простое приложение React] (#h-a-simple-react-app)

  1. JSON.parse() и JSON.stringify()

  1. XHR

  1. Выбор

  1. Аксиос

Простое приложение React


Теперь нам нужен клиент! На том же уровне, что и папка вашего сервера, создайте папку с именем client. Перейдите в папку в терминале и запустите npm install react.


После завершения установки запустите npx create-react-app <app-name> и следуйте инструкциям. Когда вы видите <word> в коде, это означает замену <word> вашим собственным новым словом без < >. Поэтому для своего кода я запустил npx create-react-app http101. npx поставляется вместе с npm. Где npm устанавливает пакеты, npx выполняет/запускает их. create-react-app создаст все файлы, необходимые для приложения React.


После того, как это будет сделано, в дополнение к новым папкам и файлам вы должны увидеть «Успех! Создано <app-name>» и другие журналы успешной сборки в вашем терминале. Запустите npm start, и вы должны увидеть журналы сборки и сообщение «Компилировано успешно!». Ваш браузер должен открыть новую вкладку с переходом по URL-адресу http://localhost:3000/ с отображенным шаблонным приложением React.


Как и в случае с сервером Node.js Express, используйте Ctrl + C, чтобы закрыть приложение. В отличие от сервера, сборка для разработки React будет отслеживать изменения и перестраиваться для вас.


Откройте client > src > index.js в текстовом редакторе. Этот файл является точкой входа в JavaScript. Другими словами, любые создаваемые нами компоненты необходимо импортировать сюда, чтобы они отображались при запуске приложения. Я импортирую свои 3 компонента следующим образом:


```javascript


импортировать React из «реагировать»;


импортировать ReactDOM из 'react-dom';


импортировать './index.css';


импортировать XHR из './Components/XHR';


импортировать Fetch из './Components/Fetch';


импортировать Axios из './Components/Axios';


импортировать reportWebVitals из './reportWebVitals';


ReactDOM.render(




<Получить />


<Аксиос />


,


document.getElementById('корень')


// Если вы хотите начать измерение производительности в своем приложении, передайте функцию


// для регистрации результатов (например: reportWebVitals(console.log))


// или отправить на конечную точку аналитики. Узнайте больше: https://bit.ly/CRA-vitals


отчетWebVitals();


В папке src, созданной приложением create-react-app, я создал папку с именем Components и добавил три файла компонентов: XHR.js, Fetch.js и Axios.js. Структура моего компонента Fetch выглядит так:


```javascript


импортировать React из «реагировать»;


функция выборки () {


вернуть (


"Вот как я делаю Fetch вещь."


экспортировать выборку по умолчанию;


Два других выглядят почти одинаково. Когда я запускаю npm start из своего терминала и вкладка моего браузера открывает http://localhost:3000, я вижу отображаемые строки всех трех моих компонентов.


3 строки, отображаемые на странице браузера - "XOXO -HR." «Вот как я делаю Fetch вещью». «Я изоморфен! (="


JSON.parse() и JSON.stringify()


Прежде чем мы перейдем к отдельному коду HTTP-запросов, давайте поговорим о встроенных в JavaScript методах преобразования JSON в JavaScript и наоборот. JSON.parse() берет объект или массив JSON и превращает его в действительный JavaScript. JSON.stringify() принимает действительный код JavaScript и превращает его в действительный JSON, иногда называемый строкой JSON.


В следующем блоке кода первый журнал выведет объект JavaScript, а второй выведет строку JSON.


```javascript


пусть пряжа = JSON.parse({


"пряжа": {


"идентификатор": 5,


"name": "Wonderland Yarns & Frabjous Fibers Мэри Энн",


«вес»: «Легкая аппликатура»,


"метров": 539,5


console.log(пряжа)


пусть newBody = JSON.stringify (пряжа)


console.log(newBody)


Он вручную делает то, что анализатор тела express.json() делал для нас на сервере Express.


XHR


Нам не нужно импортировать XMLHttpRequest в наше приложение React — он уже доступен, потому что вы пишете JavaScript для браузера. Для каждого запроса нам нужно будет создать экземпляр XHR и построить запрос, используя несколько методов.


ПОЛУЧАТЬ


Чтобы построить GET-запрос к моей конечной точке /yarn, я создаю экземпляр объекта XHR, который я назвал gXHR, открываю запрос, передавая метод и URL-адрес, а затем отправляю запрос. Наконец, я пишу функцию gXHR.onload() для обработки того, что происходит при получении ответа. В моей функции gXHR.onload() я анализирую полученный JSON в действительный объект JavaScript с помощью JSON.parse() и регистрирую первый элемент в массиве, который был возвращен.


```javascript


функция getRequest() {


// создаем объект запроса


пусть gXHR = новый XMLHttpRequest()


// устанавливаем метод и URL


gXHR.open("ПОЛУЧИТЬ", "http://localhost:8080/yarn")


// отправляем GET-запрос


gXHR.отправить()


// что происходит при получении ответа


gXHR.onload = функция () {


если (gXHR.status !== 200) {


console.log(gXHR.status, gXHR.statusText)


} еще {


пусть нити = JSON.parse(gXHR.response)


console.log (пряжа [0])


.onload() — это слушатель, по сути, цикл, который выполняется до тех пор, пока метод .send() не завершится. Функция, которую я написал и назначил .onload(), является функцией обратного вызова, которая запускается после завершения HTTP-запроса.


СООБЩЕНИЕ


Запрос POST выглядит аналогично, но мы также должны передать тело. Я начинаю с определения своего тела POST и передачи его в JSON.stringify(), чтобы преобразовать объект JavaScript в JSON. Я также должен установить заголовок «Content-Type», чтобы XHR знал, что нужно отправлять тело в формате JSON. Затем, когда я создаю свой запрос, я передаю свою строку JSON методу pHXR.send(). Наконец, я не JSON.parse() ответ в pXHR.onload(), потому что ответ является строкой.


```javascript


функция postRequest () {


пусть тело = JSON.stringify({


пряжа: {


идентификатор: 5,


название: "Wonderland Yarns & Frabjous Fibers Mary Ann",


вес: "Легкая аппликатура",


метров: 539,5


пусть pXHR = новый XMLHttpRequest()


pXHR.open("POST", "http://localhost:8080/yarn/create")


// устанавливаем заголовок запроса


pXHR.setRequestHeader('Тип контента', 'приложение/json; charset=utf-8')


pXHR.send(тело)


pXHR.onload = функция () {


если (pXHR.status !== 200) {


console.log(pXHR.status, pXHR.statusText)


} еще {


console.log(pXHR.ответ)


УДАЛЯТЬ


Наконец, мой запрос DELETE:


```javascript


функция удаления запроса () {


пусть dXHR = новый XMLHttpRequest()


dXHR.open("УДАЛИТЬ", 'http://localhost:8080/yarn/delete/3')


dXHR.отправить()


dXHR.onload = функция () {


если (dXHR.status !== 200) {


console.log(dXHR.status, dXHR.statusText)


} еще {


console.log(dXHR.ответ)


Если бы это было реальное приложение, я бы передал идентификатор пряжи, которую я хотел удалить, в deleteRequest() и динамически добавил его к URL-адресу в строке шаблона, например:


```javascript


http://localhost:8080/yarn/delete/${id}


Однако передача идентификатора обработчику onClick в React — это учебник для другого раза.


Собираем все вместе


Я использую эти функции как обработчики onClick для трех кнопок:


```javascript


вернуть (


<раздел>






Для тестирования я запускаю клиент в одном терминале с помощью npm start и сервер во втором терминале с помощью node app.js. В браузере смотрю вкладку консоли в инструментах разработчика браузера. Когда я нажимаю кнопки, появляются разные строки, которые я ожидаю увидеть.


[ ![Кнопки GET, POST и DELETE из компонента XHR отображаются на вкладке браузера. На вкладке консоли инструментов разработчика Chrome находятся 3 строковых ответа, которые мы ожидаем от сервера. (https://res.cloudinary.com/practicaldev/image/fetch/s--GM-2l5Op--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws. com/uploads/articles/exl5q0g4r7xyy2calklb.png)


Мы построили наш первый полноценный HTTP-разговор! Кнопки запускают JavaScript, который создает и кодирует HTTP-запрос, а затем отправляет его на наш сервер. Наш сервер получает HTTP-запрос, декодирует его и на основе инструкций отправляет обратно закодированное сообщение запроса. Когда клиент получает закодированное сообщение запроса, он декодирует его и записывает часть его в консоль.


Принести


Работая в основном с более новыми HTTP-пакетами на данный момент, XHR кажется мне очень ручным. Чтобы написать один запрос, мы должны использовать несколько методов. С помощью Fetch мы можем написать запрос GET в одну строку. Fetch также является веб-API, поэтому нам не нужно его импортировать. Нам даже не нужно создавать экземпляр — fetch() это отдельная функция.


ПОЛУЧАТЬ


Вот однострочный GET-запрос:


```javascript


функция getRequest() {


выборка("http://локальный:8080/пряжа")


.тогда(ответ => ответ.json())


.затем(данные => console.log(данные))


.catch(ошибка => console.log(ошибка))


fetch() делает за нас много работы. Поскольку мы не передавали параметры конфигурации, Fetch использует параметры по умолчанию. Метод автоматически устанавливается на GET. В первом .then() ответ response.json() использует встроенный анализатор JSON Fetch для преобразования тела JSON в JavaScript.


Точно так же следующие несколько строк делают многое из нескольких символов. Фактически, они находятся на новых строках для удобочитаемости для людей, что касается JavaScript, на самом деле все это одна строка.


```javascript


fetch("http://localhost:8080/yarn").then(response => response.json()).then(data => console.log(data[0])).catch(error => console. журнал (ошибка))


Поскольку Fetch основан на промисах под капотом, он возвращает объект промиса. Это означает, что мы можем использовать связанные функции .then() и .catch() для обработки результата HTTP-запроса. Таким образом, этот код говорит, что после того, как объект обещания будет возвращен как выполненный, возьмите тело ответного сообщения и проанализируйте JSON. Затем возьмите только что проанализированные данные и запишите первый результат в массив. Если вместо этого объект обещания возвращается как неудавшийся, перехватите его и запишите ошибку.


Одновременное изучение синтаксиса стрелочных функций и асинхронной цепочки может сбивать с толку — я знаю по опыту. Функция .then() ожидает выполнения функции до ее завершения, а затем выполняет переданную ей функцию. Мы могли бы переписать это так:


```javascript


функция parseData(ответ) {


ответ.json()


fetch("http://localhost:8080/yarn").then(parseData(ответ))


Не говоря уже о том, что это по сути похоже на создание обратного вызова, но за пределами функции, которая должна быть запущена до выполнения обратного вызова. Мы могли бы переписать функцию getRequest, используя синтаксис async/await и обратный вызов с тем же результатом:


```javascript


функция parseData(ответ) {


вернуть ответ.json()


асинхронная функция getFetch() {


выборка("http://локальный:8080/пряжа")


функция getRequest (обратный вызов) {


пусть ответ = ожидание getFetch()


обратный вызов (ответ)


получить запрос (данные анализа)


Заметьте, я не написал никакой обработки ошибок для замены .catch(). .catch() предназначен для обработки ошибок, возникающих в запросе Fetch. Это вызвано ошибкой JavaScript. Чтобы обработать ответ с кодом состояния 500 или ошибкой сервера, я должен был бы проверить ответ после того, как я его получил, чтобы убедиться, что это ошибка. Мы поговорим об этом подробнее в части 4.


СООБЩЕНИЕ


Чтобы POST-запрос к моей конечной точке /yarn/create работал, нам нужно передать параметры конфигурации в метод fetch(). Я начинаю с создания своего тела и преобразования его в JSON. Затем, когда я создаю свой запрос на выборку, я передаю объект конфигурации после своего URL-адреса. Наконец, поскольку ответ является строкой, мы должны проанализировать его с помощью .text() вместо .json(), прежде чем мы сможем вывести его на консоль.


```javascript


функция postRequest () {


пусть bodyString = JSON.stringify({


пряжа: {


идентификатор: 5,


название: "Wonderland Yarns & Frabjous Fibers Mary Ann",


вес: "Легкая аппликатура",


метров: 539,5


fetch("http://localhost:8080/пряжа/создать", {


метод: "ПОСТ",


заголовки: {


«Тип контента»: «приложение/json»


тело: bodyString


}).затем(ответ => ответ.текст())


.затем(данные => console.log(данные))


.catch(ошибка => console.log(ошибка))


УДАЛЯТЬ


Для метода DELETE также требуется объект конфигурации и метод .text() для разбора тела.


```javascript


функция удаления запроса () {


fetch("http://localhost:8080/yarn/delete/2", {


метод: "УДАЛИТЬ"


.тогда(ответ => ответ.текст())


.затем(данные => console.log(данные))


.catch(ошибка => console.log(ошибка))


Собираем все вместе


Как и в случае с моим компонентом XHR, я подключил эти три функции к трем кнопкам. Когда я запускаю свой клиент в одном терминале и свой сервер в другом и нажимаю на них, ожидаемые ответы записываются в консоль.


[ ![Два ряда кнопок GET, POST и DELETE из компонентов XHR и Fetch отображаются на вкладке браузера. На вкладке консоли инструментов разработчика Chrome находятся 3 строковых ответа, которые мы ожидаем от сервера. (https://res.cloudinary.com/practicaldev/image/fetch/s--Y4vJJgJN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/ загрузки/статьи/wuqh6cnchqk61krh2dgt.png)


Аксиос


Axios — это пакет npm, поэтому я запускаю «npm install axios» в своем терминале, чтобы установить его. Я также должен импортировать его вверху моего файла:


```javascript


импортировать аксиомы из 'axios';


ПОЛУЧАТЬ


Теперь, когда он импортирован, мы можем использовать метод .get() для написания запроса. Поскольку Axios также использует промисы, мы все еще можем использовать .then() и .catch().


```javascript


функция getRequest() {


axios.get('http://localhost:8080/yarn')


.тогда(ответ => console.log(ответ.данные[0]))


.catch(ошибка => console.log(ошибка))


Сразу видно, насколько этот формат ближе к серверу Express, чем XHR. Кроме того, вы, возможно, заметили, что мне не нужно анализировать тело ответа — Axios делает это за нас. В рамках этого форматирования изменяется структура объекта ответа, на который мы можем ссылаться, — вместо response.body я должен ссылаться на response.data. Поскольку у них это есть [в документах] (https://github.com/axios/axios#request-config), я знал, что этого можно ожидать. Мы углубимся в оценку формата ответа, когда вы не знаете, чего ожидать, в части 3.


СООБЩЕНИЕ


Далее, POST-запрос. Благодаря Axios мне не нужно JSON.stringify() мое тело, а метод .post() позволяет передать объект для добавления в тело после URL-адреса.


```javascript


функция postRequest () {


axios.post('http://localhost:8080/yarn/create', {


пряжа: {


идентификатор: 5,


название: "Wonderland Yarns & Frabjous Fibers Mary Ann",


вес: "Легкая аппликатура",


метров: 539,5


}).затем(ответ => console.log(ответ.данные))


.catch(ошибка => console.log(ошибка))


Мне даже не нужно было передавать заголовок — Axios пытается JSON.stringify() все тела запросов и JSON.parse() все тела ответов. Мы расскажем, как использовать объект конфигурации для установки заголовков (а также метода и аутентификации) в части 4.


УДАЛЯТЬ


Наконец, запрос DELETE к моей конечной точке /yarn/delete/:id, очень похожий на запрос GET:


```javascript


функция удаления запроса () {


axios.delete('http://localhost:8080/yarn/delete/1')


.затем(ответ => console.log(ответ.данные))


.catch(ошибка => console.log(ошибка))


Собираем все вместе


Я снова подключаю эти функции к кнопкам, и теперь у меня есть 3 ряда уродливых кнопок, возвращающих ожидаемые ответы.


[ ![Три ряда кнопок GET, POST и DELETE из компонентов XHR, Fetch и Axios отображаются на вкладке браузера. На вкладке консоли инструментов разработчика Chrome находятся 3 строковых ответа, которые мы ожидаем от сервера. (https://res.cloudinary.com/practicaldev/image/fetch/s--7v61hYhT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/ загрузки/статьи/s8qp28wuuz6t07itrxaj.png)


Заключение


Начиная с XHR и заканчивая Axios, вы действительно можете увидеть, как пакеты HTTP-запросов и асинхронные методы для JavaScript развивались и абстрагировались на протяжении многих лет. Поскольку под капотом так много всего происходит, а сами методы просты в использовании, многие из этих концепций не учитываются при обучении студентов использованию HTTP. Я надеюсь, что эта серия поможет вам лучше понять внутреннюю работу HTTP-сообщений в целом.


Если вы остались в замешательстве или у вас есть какие-либо вопросы по любой из тем, которые я затронул в этой части серии, пожалуйста, не стесняйтесь оставлять комментарии!


Теперь мы знаем, как в JavaScript генерируются запросы и ответы. Следите за «Руководством по HTTP для начинающих — часть 4: API». Как только я закончу его писать, следующая часть серии будет посвящена оценке API, созданных другими людьми, и их использованию в вашем собственном приложении. Это будет включать аутентификацию, отображение того, что мы получаем от API в браузере, обработку ошибок и многое другое.


Также опубликовано здесь



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE