Как разобрать тело multipart/form-data с Koa?
Потому что я потратил некоторое (слишком много) время на выяснение этого простого требования. Я документирую здесь способ достижения разбора тела multipart/form-data
с Koa.
В моем случае причиной путаницы было количество доступных альтернатив:
И я хотел найти самый минималистский/близкий способ express/koa/node
/философию делать вещи.
Так вот оно. Ниже. В принятом ответе. Надеюсь это поможет.
Ответы
Ответ 1
Вы должны использовать koa-multer, как указано в официальной вики Коа.
Таким образом, простая настройка будет выглядеть так:
const koa = require('koa');
const multer = require('koa-multer');
const app = koa();
app.use(multer());
app.use(function *() {
this.body = this.req.body;
});
Несколько примечаний:
- Multer будет анализировать только тела запросов типа
multipart/form-data
- Обратите внимание, что использование
this.req.body
вместо this.req.body
перегружает this.request
(не уверен, что это намеренно, но это сбивает с толку наверняка... Я бы ожидал, что разобранное body
будет доступно на this.request
...)
И FormData
эту HTML-форму как FormData
:
<form>
<input type="hidden" name="topsecret" value="1">
<input type="text" name="area51[lat]" value="37.235065">
<input type="text" name="area51[lng]" value="-115.811117">
...
</form>
Предоставляет вам доступ к вложенным свойствам, как ожидалось:
// -> console.log(this.req.body)
{
"topsecret": 1,
"area51": {
"lat": "37.235065",
"lng": "-115.811117",
}
}
Ответ 2
Для Koa2 вы можете использовать async-busboy, поскольку другие решения не поддерживают обещания или async/await.
Пример из документов:
import asyncBusboy from 'async-busboy';
// Koa 2 middleware
async function(ctx, next) {
const {files, fields} = await asyncBusboy(ctx.req);
// Make some validation on the fields before upload to S3
if ( checkFiles(fields) ) {
files.map(uploadFilesToS3)
} else {
return 'error';
}
}
Ответ 3
Я прошел такое же расследование, как и вы, и здесь есть другие способы получить парсинг тела multipart/form-data
с Koa.
co-busboy:
var koa = require('koa');
var parse = require('co-busboy');
const app = koa();
app.use(function* (next) {
// the body isn't multipart, so busboy can't parse it
if (!this.request.is('multipart/*')) return yield next;
var parts = parse(this),
part,
fields = {};
while (part = yield parts) {
if (part.length) {
// arrays are busboy fields
console.log('key: ' + part[0]);
console.log('value: ' + part[1]);
fields[part[0]] = part[1];
} else {
// it a stream, you can do something like:
// part.pipe(fs.createWriteStream('some file.txt'));
}
}
this.body = JSON.stringify(fields, null, 2);
})
koa-body:
var koa = require('koa');
var router = require('koa-router');
var koaBody = require('koa-body')({ multipart: true });
const app = koa();
app.use(router(app));
app.post('/', koaBody, function *(next) {
console.log(this.request.body.fields);
this.body = JSON.stringify(this.request.body, null, 2);
});
В обоих случаях у вас будет ответ вроде:
{
"topsecret": 1,
"area51": {
"lat": "37.235065",
"lng": "-115.811117",
}
}
Но лично я предпочитаю, как работает куа-тело. Кроме того, совместим с другим промежуточным программным обеспечением, например, с проверкой каа.
Кроме того, если вы укажете загрузчик в koa-body, он сохранит загруженный файл для вас:
var koaBody = require('koa-body')({
multipart: true,
formidable: { uploadDir: path.join(__dirname, 'tmp') }
});