Разбирайте multipart/form-data из тела как строки на AWS Lambda
Я рад видеть AWS теперь поддерживает multipart/form-data на AWS Lambda, но теперь, когда исходные данные находятся в моей лямбда как я могу его обработать?
Я вижу multiparty - хорошая многочастная библиотека в Node для многопроцессорной обработки, но ее конструктор ожидает запроса, а не сырья строка.
Входное сообщение, которое я получаю на моей функции Lambda (после применения шаблона отображения тела):
{ "rawBody": "--ce0741b2-93d4-4865-a7d6-20ca51fe2689\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\nmultipart/mixed; boundary=\"------------020601070403020003080006\"\r\n--ce0741b2-93d4-4865-a7d6-20ca51fe2689\r\nContent-Disposition: form-data; name=\"Date\"\r\n\r\nFri, 26 Apr 2013 11:50:29 -0700\r\n--ce0741b2-93d4-4865-a7d6-20ca51fe2689\r\nContent-Disposition: form-data; name=\"From\"\r\n\r\nBob <[email protected]>\r\n--ce0741b2-93d4-4865-a7d6-20ca51fe2689\r\nContent-Disposition: form-data; name=\"In-Reply-To\"\r...
и т.д. и некоторые данные файла.
Используемый мной шаблон отображения тела
{
"rawBody" : "$util.escapeJavaScript($input.body).replaceAll("\\'", "'")"
}
Как я могу проанализировать эти данные для acecss полей и файлов, отправленных в мою функцию Lambda?
Ответы
Ответ 1
Это сработало для меня - с помощью Busboy
кредиты причитаются Parse multipart/form-data из буфера в Node.js, из которого я скопировал большую часть этого.
const busboy = require('busboy');
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS, POST',
'Access-Control-Allow-Headers': 'Content-Type'
};
function handler(event, context) {
var contentType = event.headers['Content-Type'] || event.headers['content-type'];
var bb = new busboy({ headers: { 'content-type': contentType }});
bb.on('file', function (fieldname, file, filename, encoding, mimetype) {
console.log('File [%s]: filename=%j; encoding=%j; mimetype=%j', fieldname, filename, encoding, mimetype);
file
.on('data', data => console.log('File [%s] got %d bytes', fieldname, data.length))
.on('end', () => console.log('File [%s] Finished', fieldname));
})
.on('field', (fieldname, val) =>console.log('Field [%s]: value: %j', fieldname, val))
.on('finish', () => {
console.log('Done parsing form!');
context.succeed({ statusCode: 200, body: 'all done', headers });
})
.on('error', err => {
console.log('failed', err);
context.fail({ statusCode: 500, body: err, headers });
});
bb.end(event.body);
}
module.exports = { handler };
Ответ 2
Основываясь на @AvnerSo: s ответ, здесь более простая версия функции, которая получает тело запроса и заголовки в качестве параметров и возвращает обещание объекта, содержащего поля формы и значения (пропуски файлов):
const parseForm = (body, headers) => new Promise((resolve, reject) => {
const contentType = headers['Content-Type'] || headers['content-type'];
const bb = new busboy({ headers: { 'content-type': contentType }});
var data = {};
bb.on('field', (fieldname, val) => {
data[fieldname] = val;
}).on('finish', () => {
resolve(data);
}).on('error', err => {
reject(err);
});
bb.end(body);
});
Ответ 3
Если вы хотите получить готовый объект, вот функция, которую я использую. Он возвращает обещание и обрабатывает ошибки:
import Busboy from 'busboy';
import YError from 'yerror';
import getRawBody from 'raw-body';
const getBody = (content, headers) =>
new Promise((resolve, reject) => {
const filePromises = [];
const data = {};
const parser = new Busboy({
headers,
},
});
parser.on('field', (name, value) => {
data[name] = value;
});
parser.on('file', (name, file, filename, encoding, mimetype) => {
data[name] = {
filename,
encoding,
mimetype,
};
filePromises.push(
getRawBody(file).then(rawFile => (data[name].content = rawFile))
);
});
parser.on('error', err => reject(YError.wrap(err)));
parser.on('finish', () =>
resolve(Promise.all(filePromises).then(() => data))
);
parser.write(content);
parser.end();
})
Ответ 4
Busboy не работает для меня в случае "файла". Это не вызвало никаких исключений, так что я не смог обработать исключение в лямбде вообще.
Я использую aws-lambda-multipart-parser lib не так уж и сложно. Он просто анализирует данные из event.body и возвращает данные в виде буфера или текста.
Использование:
const multipart = require('aws-lambda-multipart-parser');
const result = multipart.parse(event, spotText) // spotText === true: Buffer and spotText === false: String
Данные ответа:
{
"file": {
"type": "file",
"filename": "lorem.txt",
"contentType": "text/plain",
"content": {
"type": "Buffer",
"data": [ ... byte array ... ]
} or String
},
"field": "value"
}