Предположим, что мы хотим программно выполнить get
запрос к Хекслету.
В nodejs
сделать это довольно просто:
import http from 'http';
http.get('http://ru.hexlet.io/my', res => {
console.log(res.statusCode);
});
Вторым параметром передается колбек, который будет вызван после получения
ответа. Он также принимает на вход объект response
, который содержит
в себе параметры ответа.
Этих параметров внутри response
очень много, и только некоторые из них
наиболее часто используются или могут быть нам интересны. В первую очередь
это следующий набор:
// response
{
headers: /* ... */,
statusCode: 301,
statusMessage: 'Moved Permanently',
};
Также get
позволяет передавать первым параметром не адрес, а набор
опций, из которого будет составлен адрес. Такое бывает полезно, когда
у нас нет готового адреса, но есть его части:
import http from 'http';
// headers, method, port, ...
const options = {
hostname: 'ru.hexlet.io',
path: 'my',
};
http.get(options, res => {
console.log(res.statusCode);
});
Обо всех доступных опциях можно прочитать в официальной документации, а из самых распространенных мы выделим следующие:
- headers — объект, в котором ключ — это название заголовка
- method — например,
GET
- port
- hostname
- path
Body
В запросе выше не хватает одной важной детали: получение тела ответа.
Тут нас поджидает небольшой сюрприз. Объект response
не содержит внутри
себя тело ответа. Связано это с тем, что ответ может приходить чанками,
и response
дает возможность получать эти чанки сразу и независимо друг от друга.
С одной стороны, это более гибкая возможность, которая позволяет работать с большим
телом, без того чтобы занимать много оперативной памяти; с другой стороны, для
простых запросов приходится доставать тело немного более сложным способом, чем хотелось
бы. Но, в конечном итоге, все сводится к понятному коду, который нужно просто запомнить.
http.get(url, res => {
const body = [];
res.on('data', chunk => {
body.push(chunk.toString());
}).on('end', () => {
const html = body.join();
console.log(html);
});
});
Как видно из примера выше, объект response
представляет из себя eventEmitter
с событиями data
и end
. Первое вызывается после получения очередного чанка с
данными, второе вызывается после того, как все данные пришли и нужно обозначить
конец обработки.
Buffer
Из кода сбора чанков в body
можно сделать вывод, что chunk
– это не строка. Это
действительно так, chunk
– это объект типа Buffer
, который предназначен для
хранения потока байтов в виде массива фиксированного размера. Нужно это по той простой
причине, что данные, передаваемые по http
, не обязательно имеют текстовое представление.
Возможна передача также и бинарных данных, таких как картинки, архивы и тому подобное.
const str = 'string as bytes';
const buffer = new Buffer(str, 'utf-8');
console.log(buffer);
// <Buffer 73 74 72 69 6e 67 20 61 73 20 62 79 74 65 73>
buffer.toString();
// string as bytes
Errors
Во время выполнения запроса может произойти все, что угодно. Библиотека http
обрабатывает эти ошибки и кидает соответствующие исключения. К таким ошибкам относятся например:
- Проблемы с
DNS
- Ошибки уровня
tcp
- Ошибки парсинга
http
ответа
Если для программы важно не завершаться в случае таких ошибок, то можно ловить
событие error
на объекте request
, который возвращается после выполнения get
запроса и производить желаемое действие:
import http from 'http';
const uri = 'http://ru.hexlet.io/my';
const req = http.get(uri, res => {
console.log(res.statusCode);
});
req.on('error', e => {
console.log(`Got error: ${e.message}`);
});
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты