req.body 是 [Object: null prototype] {} 并且 req.files 在使用 multer 处理包含表单数据的 POST 请求时为空
req.body is [Object: null prototype] {} and req.files is empty when using multer to handle POST request containing form data
我正在尝试使用 Postman 将表单数据发送到托管在 Firebase 函数上的快速服务器。
这是我用来接收 POST 请求的代码:
import * as functions from 'firebase-functions';
import express = require('express');
import multer = require('multer');
import * as bodyParser from 'body-parser';
const app = express();
const upload = multer().array("attachment");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', upload, (req, res) => {
console.log(req.body);
console.log(req.files);
res.sendStatus(200);
});
export const server = functions.https.onRequest(app);
这是 postman 设置
当我发送 post 请求时,req.body 和 req.files 记录如下:
i functions: Beginning execution of "server"
> [Object: null prototype] {}
> []
i functions: Finished "server" in ~1s
我觉得它应该非常简单...我做错了什么?
编辑:
这里要求的是请求头
{
'postman-token': '816a8871-bb12-470f-93f8-13cb6024815d',
host: 'localhost:5001',
'content-type': 'multipart/form-data; boundary=--------------------------115218701862318827186009',
'content-length': '316657',
connection: 'close'
}
这是 curl 代码
curl --location --request POST 'http://localhost:5001/hosting-name/us-central1/server/upload' --form 'testKey="testValue"' --form 'attachment=@ <path_to_your_file>"'
感谢这个博客 post 我弄明白了:https://mikesukmanowsky.com/firebase-file-and-image-uploads/
Firebase 和 Multer 不能一起使用。我调整了博客 post 中的代码以在我的 Typescript 项目中工作:
index.ts
import * as functions from 'firebase-functions';
import express = require('express');
import * as bodyParser from 'body-parser';
import formMiddlware from "./formMiddleware";
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', formMiddlware, (req: any, res: any) => {
console.log(req.body);
console.log(req.files);
res.sendStatus(200);
});
export const server = functions.https.onRequest(app);
formMiddleware.ts
import * as Busboy from "busboy";
import os from "os";
import fs from "fs";
import path from "path";
type Dict = {
[key: string]: any
}
function formMiddlware (req: any , res: any, next: any) {
// See https://cloud.google.com/functions/docs/writing/http#multipart_data
const busboy = new Busboy.default({
headers: req.headers,
limits: {
// Cloud functions impose this restriction anyway
fileSize: 10 * 1024 * 1024,
}
});
const fields: Dict = {};
const files: any[] = [];
const fileWrites: any[] = [];
// Note: os.tmpdir() points to an in-memory file system on GCF
// Thus, any files in it must fit in the instance's memory.
const tmpdir = os.tmpdir();
busboy.on('field', (key: string, value: any) => {
// You could do additional deserialization logic here, values will just be
// strings
fields[key] = value;
});
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const filepath = path.join(tmpdir, filename);
console.log(`Handling file upload field ${fieldname}: ${filename} (${filepath})`);
const writeStream = fs.createWriteStream(filepath);
file.pipe(writeStream);
fileWrites.push(new Promise((resolve, reject) => {
file.on('end', () => writeStream.end());
writeStream.on('finish', () => {
fs.readFile(filepath, (err, buffer) => {
const size = Buffer.byteLength(buffer);
console.log(`${filename} is ${size} bytes`);
if (err) {
return reject(err);
}
files.push({
fieldname,
originalname: filename,
encoding,
mimetype,
buffer,
size,
});
try {
fs.unlinkSync(filepath);
} catch (error) {
return reject(error);
}
resolve();
});
});
writeStream.on('error', reject);
}));
});
busboy.on('finish', () => {
Promise.all(fileWrites)
.then(() => {
req.body = fields;
req.files = files;
next();
})
.catch(next);
});
busboy.end(req.rawBody);
}
export default formMiddlware;
我正在尝试使用 Postman 将表单数据发送到托管在 Firebase 函数上的快速服务器。 这是我用来接收 POST 请求的代码:
import * as functions from 'firebase-functions';
import express = require('express');
import multer = require('multer');
import * as bodyParser from 'body-parser';
const app = express();
const upload = multer().array("attachment");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', upload, (req, res) => {
console.log(req.body);
console.log(req.files);
res.sendStatus(200);
});
export const server = functions.https.onRequest(app);
这是 postman 设置
当我发送 post 请求时,req.body 和 req.files 记录如下:
i functions: Beginning execution of "server"
> [Object: null prototype] {}
> []
i functions: Finished "server" in ~1s
我觉得它应该非常简单...我做错了什么?
编辑:
这里要求的是请求头
{
'postman-token': '816a8871-bb12-470f-93f8-13cb6024815d',
host: 'localhost:5001',
'content-type': 'multipart/form-data; boundary=--------------------------115218701862318827186009',
'content-length': '316657',
connection: 'close'
}
这是 curl 代码
curl --location --request POST 'http://localhost:5001/hosting-name/us-central1/server/upload' --form 'testKey="testValue"' --form 'attachment=@ <path_to_your_file>"'
感谢这个博客 post 我弄明白了:https://mikesukmanowsky.com/firebase-file-and-image-uploads/
Firebase 和 Multer 不能一起使用。我调整了博客 post 中的代码以在我的 Typescript 项目中工作:
index.ts
import * as functions from 'firebase-functions';
import express = require('express');
import * as bodyParser from 'body-parser';
import formMiddlware from "./formMiddleware";
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', formMiddlware, (req: any, res: any) => {
console.log(req.body);
console.log(req.files);
res.sendStatus(200);
});
export const server = functions.https.onRequest(app);
formMiddleware.ts
import * as Busboy from "busboy";
import os from "os";
import fs from "fs";
import path from "path";
type Dict = {
[key: string]: any
}
function formMiddlware (req: any , res: any, next: any) {
// See https://cloud.google.com/functions/docs/writing/http#multipart_data
const busboy = new Busboy.default({
headers: req.headers,
limits: {
// Cloud functions impose this restriction anyway
fileSize: 10 * 1024 * 1024,
}
});
const fields: Dict = {};
const files: any[] = [];
const fileWrites: any[] = [];
// Note: os.tmpdir() points to an in-memory file system on GCF
// Thus, any files in it must fit in the instance's memory.
const tmpdir = os.tmpdir();
busboy.on('field', (key: string, value: any) => {
// You could do additional deserialization logic here, values will just be
// strings
fields[key] = value;
});
busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
const filepath = path.join(tmpdir, filename);
console.log(`Handling file upload field ${fieldname}: ${filename} (${filepath})`);
const writeStream = fs.createWriteStream(filepath);
file.pipe(writeStream);
fileWrites.push(new Promise((resolve, reject) => {
file.on('end', () => writeStream.end());
writeStream.on('finish', () => {
fs.readFile(filepath, (err, buffer) => {
const size = Buffer.byteLength(buffer);
console.log(`${filename} is ${size} bytes`);
if (err) {
return reject(err);
}
files.push({
fieldname,
originalname: filename,
encoding,
mimetype,
buffer,
size,
});
try {
fs.unlinkSync(filepath);
} catch (error) {
return reject(error);
}
resolve();
});
});
writeStream.on('error', reject);
}));
});
busboy.on('finish', () => {
Promise.all(fileWrites)
.then(() => {
req.body = fields;
req.files = files;
next();
})
.catch(next);
});
busboy.end(req.rawBody);
}
export default formMiddlware;