В настройке Cloud Functions действительно произошли серьезные изменения, которые вызвали эту проблему. Это связано с тем, как работает промежуточное ПО, которое применяется ко всем приложениям Express (включая приложение по умолчанию), используемым для обслуживания функций HTTPS. По сути, облачные функции будут анализировать тело запроса и решать, что с ним делать, оставляя необработанное содержимое тела в буфере в req.rawBody
. Вы можете использовать это для непосредственного анализа вашего многокомпонентного контента, но вы не можете сделать это с помощью промежуточного программного обеспечения (например, multer).
Вместо этого вы можете использовать модуль под названием busboy для непосредственной работы с необработанным содержимым тела. Он может принять буфер rawBody
и перезвонит вам с найденными файлами. Вот пример кода, который будет перебирать весь загруженный контент, сохранять его как файлы, а затем удалять их. Вы, очевидно, захотите сделать что-то более полезное.
const path = require('path');
const os = require('os');
const fs = require('fs');
const Busboy = require('busboy');
exports.upload = functions.https.onRequest((req, res) => {
if (req.method === 'POST') {
const busboy = new Busboy({ headers: req.headers });
// This object will accumulate all the uploaded files, keyed by their name
const uploads = {}
// This callback will be invoked for each file uploaded
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
console.log(`File [${fieldname}] filename: ${filename}, encoding: ${encoding}, mimetype: ${mimetype}`);
// Note that os.tmpdir() is an in-memory file system, so should only
// be used for files small enough to fit in memory.
const filepath = path.join(os.tmpdir(), fieldname);
uploads[fieldname] = { file: filepath }
console.log(`Saving '${fieldname}' to ${filepath}`);
file.pipe(fs.createWriteStream(filepath));
});
// This callback will be invoked after all uploaded files are saved.
busboy.on('finish', () => {
for (const name in uploads) {
const upload = uploads[name];
const file = upload.file;
res.write(`${file}\n`);
fs.unlinkSync(file);
}
res.end();
});
// The raw bytes of the upload will be in req.rawBody. Send it to busboy, and get
// a callback when it's finished.
busboy.end(req.rawBody);
} else {
// Client error - only support POST
res.status(405).end();
}
})
Помните, что файлы, сохраненные во временном пространстве, занимают память, поэтому их размеры должны быть ограничены до 10 МБ. Для более крупных файлов вы должны загрузить их в облачное хранилище и обработать их с помощью триггера хранилища.
Также имейте в виду, что выбор промежуточного программного обеспечения по умолчанию, добавляемый Cloud Functions, в настоящее время не добавляется в локальный эмулятор через firebase serve
. Так что этот пример не будет работать (rawBody не будет доступен) в этом случае.
Команда работает над обновлением документации, чтобы лучше понять, что происходит во время запросов HTTPS, отличающихся от стандартного приложения Express.
Предполагая, что первый байт является младшим байтом:
long value = 0;
for (int i = 0; i < by.length; i++)
{
value += ((long) by[i] & 0xffL) << (8 * i);
}
Is первый байт - самый значимый, тогда он немного отличается:
long value = 0;
for (int i = 0; i < by.length; i++)
{
value = (value << 8) + (by[i] & 0xff);
}
Заменить long на BigInteger , если у вас больше 8 байт.
Спасибо Аарону Дигулле за исправление моих ошибок .
long value = 0;
for (int i = 0; i < by.length; i++)
{
value += ((long) by[i] & 0xffL) << (8 * i);
}
Является ли первый байт наиболее значимым, тогда он немного отличается:
long value = 0;
for (int i = 0; i < by.length; i++)
{
value = (value << 8) + (by[i] & 0xff);
}
Замените long на BigInteger , если у вас больше 8 байтов.
Спасибо Аарону Дигулле за исправление моих ошибок.
long value = 0;
for (int i = 0; i < by.length; i++)
{
value += ((long) by[i] & 0xffL) << (8 * i);
}
Является ли первый байт наиболее значимым, тогда он немного отличается:
long value = 0;
for (int i = 0; i < by.length; i++)
{
value = (value << 8) + (by[i] & 0xff);
}
Замените long на BigInteger , если у вас больше 8 байтов.
Спасибо Аарону Дигулле за исправление моих ошибок.
Для выполнения преобразования можно использовать Buffer
, которые предоставляются как часть java.nio
пакета.
Здесь Исходный массив byte []
имеет длину 8, что соответствует размеру, соответствующему значению long
.
Во-первых, массив byte []
упакован в ByteBuffer
, а затем вызывается метод ByteBuffer.getLong
для получения значения long
:
ByteBuffer bb = ByteBuffer.wrap(new byte[] {0, 0, 0, 0, 0, 0, 0, 4});
long l = bb.getLong();
System.out.println(l);
Result
4
Я бы хотел поблагодарить dfa за указание метода ByteBuffer.getLong
в комментариях.
Хотя он может быть неприменим в этой ситуации, красота Buffer
заключается в том, чтобы взглянуть на массив с несколькими значениями.
Например, если у нас есть 8-байтовый массив,и мы хотели видеть его как два значения int
, мы могли бы обернуть массив byte []
в ByteBuffer
, который рассматривается как IntBuffer
и получить значения с помощью IntBuffer.get
:
ByteBuffer bb = ByteBuffer.wrap(new byte[] {0, 0, 0, 1, 0, 0, 0, 4});
IntBuffer ib = bb.asIntBuffer();
int i0 = ib.get(0);
int i1 = ib.get(1);
System.out.println(i0);
System.out.println(i1);
Результат:
1
4
Если это 8-байтовое числовое значение, вы можете попробовать:
BigInteger n = new BigInteger(byteArray);
Если это символьный буфер UTF-8, вы можете попробовать:
BigInteger n = new BigInteger(new String(byteArray, "UTF-8"));