Получение двоичного содержимого в node.js с помощью http.request
Я хотел бы получить двоичные данные из запроса https.
Я нашел похожий вопрос, в котором используется метод запроса " Получение бинарного содержимого в Node.js с использованием запроса" - он говорит, что установка кодировки на ноль должна работать, но это не так.
options = {
hostname: urloptions.hostname,
path: urloptions.path,
method: 'GET',
rejectUnauthorized: false,
encoding: null
};
req = https.request(options, function(res) {
var data;
data = "";
res.on('data', function(chunk) {
return data += chunk;
});
res.on('end', function() {
return loadFile(data);
});
res.on('error', function(err) {
console.log("Error during HTTP request");
console.log(err.message);
});
})
Редактировать: установка кодировки в "двоичный" также не работает
Ответы
Ответ 1
Принятый ответ не работал у меня (т.е. установил кодировку в двоичный файл), даже пользователь, который задал вопрос о том, что он не работает.
Здесь то, что сработало для меня, взято из: http://chad.pantherdev.com/node-js-binary-http-streams/
http.get(url.parse('http://myserver.com:9999/package'), function(res) {
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
}).on('end', function() {
//at this point data is an array of Buffers
//so Buffer.concat() can make us a new Buffer
//of all of them together
var buffer = Buffer.concat(data);
console.log(buffer.toString('base64'));
});
});
Изменить: Обновить ответ после предложения Semicolon
Ответ 2
Вам нужно установить кодировку в ответ, а не запросить:
req = https.request(options, function(res) {
res.setEncoding('binary');
var data = [ ];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
var binary = Buffer.concat(data);
// binary is your data
});
res.on('error', function(err) {
console.log("Error during HTTP request");
console.log(err.message);
});
});
Вот полезный ответ: Написание изображения на локальный сервер
Ответ 3
Работа на NodeJS 6.10 (и 8.10, протестирована в феврале 2019 года) в среде AWS Lambda, ни одно из вышеперечисленных решений для меня не работает.
То, что сработало для меня, было следующим:
https.get(opt, (res) => {
res.setEncoding('binary');
let chunks = [];
res.on('data', (chunk) => {
chunks.push(Buffer.from(chunk, 'binary'));
});
res.on('end', () => {
let binary = Buffer.concat(chunks);
// binary is now a Buffer that can be used as Uint8Array or as
// any other TypedArray for data processing in NodeJS or
// passed on via the Buffer to something else.
});
});
Обратите внимание на res.setEncoding('binary'); и Buffer.from(chunk, 'binary') строки. Один устанавливает кодировку ответа, а другой создает объект Buffer из строки, предоставленной в кодировке, указанной ранее.
Ответ 4
Перт Йохансон. Я хотел бы прокомментировать, чтобы поблагодарить вас за то, что вы спасли меня от рекурсивного цикла, за который я весь день рвал волосы, а затем читал (невероятно бесполезные) документы по узлам на этом, снова и снова. Найдя ваш ответ, я пошел копаться в документах, и я даже не могу найти метод res.setEncoding
документированный где-либо! Это просто показано как часть двух примеров, в которых они вызывают res.setEncoding('utf8');
Где ты это нашел или как ты это понял !?
Поскольку у меня недостаточно репутации, чтобы комментировать, я, по крайней мере, внесу что-то полезное в свой ответ: ответ Пярта Йохансона для меня сработал на 100%, я просто немного подправил его для своих нужд, потому что я использую его для загрузки и Проверьте сценарий, размещенный на моем сервере (и скомпилированный с помощью nwjc), используя nw.Window.get().evalNWBin()
в NWJS 0.36.4/Node 11.11.0:
let opt = {...};
let req = require('https').request(opt, (res) => {
// server error returned
if (200 !== res.statusCode) {
res.setEncoding('utf8');
let data = '';
res.on('data', (strData) => {
data += strData;
});
res.on('end', () => {
if (!res.complete) {
console.log('Server error, incomplete response: ' + data);
} else {
console.log('Server error, response: ' + data);
}
});
}
// expected response
else {
res.setEncoding('binary');
let data = [];
res.on('data', (binData) => {
data.push(Buffer.from(binData, 'binary'));
});
res.on('end', () => {
data = Buffer.concat(data);
if (!res.complete) {
console.log('Request completed, incomplete response, ' + data.length + ' bytes received);
} else {
console.log('Request completed, ' + data.length + ' bytes received');
nw.Window.get().evalNWBin(null, data);
}
});
}
};
Изменение: PS Я разместил это на всякий случай, если кто-то хотел знать, как обрабатывать недвоичный ответ - мой фактический код идет немного глубже и проверяет заголовок типа содержимого ответа для анализа JSON (предполагаемый сбой, то есть 400, 401, 403) или HTML (неожиданный сбой, т.е. 404 или 500)
Ответ 5
- Не
setEncoding()
метод setEncoding()
, потому что по умолчанию кодировка не назначена, и данные потока будут возвращены как объекты Buffer
- Вызовите
Buffer.from()
в on.data
обратного вызова on.data
чтобы преобразовать значение chunk
в объект Buffer
.
http.get('my_url', (response) => {
const chunks = [];
response.on('data', chunk => chunks.push(Buffer.from(chunk))) // Converte 'chunk' to a 'Buffer' object.
.on('end', () => {
const buffer = Buffer.concat(chunks);
console.log(buffer.toString('base64'));
});
});
Ответ 6
Как и другим, мне нужно было обрабатывать фрагменты двоичных данных из HTTP-ответа Node.js (он же http.IncomingMessage
).
Ни один из существующих ответов действительно не работал для моего проекта Electron 6 (в комплекте с Node.js 12.4.0, на момент публикации), кроме Pärt Johanson answer и его вариантов.
Тем не менее, даже при таком решении куски всегда поступали в обработчик response.on('data', ondata)
как объекты string
(а не как ожидаемые и желаемые объекты Buffer
). Это повлекло за собой дополнительное преобразование с Buffer.from(chunk, 'binary')
. Я получал строки независимо от того, явно ли я указал двоичное кодирование с помощью response.setEncoding('binary')
или response.setEncoding(null)
.
Единственный способ получить оригинальные чанки Buffer
- передать response
в экземпляр stream.Writable
, где я предоставляю собственный метод write
:
const https = require('https');
const { Writable } = require('stream');
async function getBinaryDataAsync(url) {
// start HTTP request, get binary response
const { request, response } = await new Promise((resolve, reject) => {
const request = https.request(url, {
method: 'GET',
headers: {
'Accept': 'application/pdf',
'Accept-Encoding': 'identity'
}
}
);
request.on('response', response =>
resolve({request, response}));
request.on('error', reject);
request.end();
});
// read the binary response by piping it to stream.Writable
const buffers = await new Promise((resolve, reject) => {
response.on('aborted', reject);
response.on('error', reject);
const chunks = [];
const stream = new Writable({
write: (chunk, encoding, notifyComplete) => {
try {
chunks.push(chunk);
notifyComplete();
}
catch(error) {
notifyComplete(error);
}
}
});
stream.on('error', reject);
stream.on('finish', () => resolve(chunks));
response.pipe(stream);
});
const buffer = Buffer.concat(buffers);
return buffer.buffer; // as ArrayBuffer
}
async function main() {
const arrayBuff = await getBinaryDataAsync('https://download.microsoft.com/download/8/A/4/8A48E46A-C355-4E5C-8417-E6ACD8A207D4/VisualStudioCode-TipsAndTricks-Vol.1.pdf');
console.log(arrayBuff.byteLength);
};
main().catch(error => console.error(error));
Обновленный, как оказалось, это поведение проявляется только для нашего сервера веб-API. Таким образом, response.on('data')
на самом деле хорошо работает для примера URL, который я использую в приведенном выше фрагменте кода, и поток для него не нужен. Это странно, хотя это специфично, я исследую это дальше.