Reputation: 170805
I create a FormData
as follows (simplified):
import FormData from 'form-data';
const createForm = async () => {
const form = new FormData();
form.append('field1', 'stringValue1');
form.append('fileField', fs.createReadStream(__filename), {
contentType: 'text/javascript',
filename: 'file.js',
});
return form;
};
Then to send it over HTTP/2 (cleartext):
// app is a FastifyInstance
await app.ready();
const { address, port } = app.server.address();
const client = http2.connect(`http://${address}:${port}`);
const request = client.request({
':method': 'POST',
':path': '/path',
'content-type': `multipart/form-data; boundary=${form.getBoundary()}`,
});
request.setEncoding('utf8');
let status;
request.on('response', (headers) => {
status = headers[':status'];
});
request.on('data', (data) => { ... });
form.pipe(request);
request.end();
await new Promise((resolve) => {
request.on('end', () => {
client.close();
resolve();
});
});
Then in the Fastify server listening to requests I have
import fastify from 'fastify';
import fastifyFormbody from '@fastify/formbody';
import fastifyMultipart from '@fastify/multipart';
const app = fastify({ http2: true, logger: logLevel === 'debug' });
const fieldSizeLimit = 1024 * 1024 * 10;
void app.register(fastifyFormbody);
void app.register(fastifyMultipart, {
attachFieldsToBody: 'keyValues',
limits: {
fieldSize: fieldSizeLimit,
fileSize: fieldSizeLimit,
},
onFile: async (part) => {
const destinationPath = path.join(bundlePath, 'uploads', part.filename);
await saveMultipartFile(part, destinationPath);
// eslint-disable-next-line no-param-reassign
part.value = {
filename: part.filename,
savedFilePath: destinationPath,
type: 'asset',
};
},
});
app.post('/path', async (req, res) => {
console.log(Object.entries(req.body));
...
});
which worked fine with HTTP/1.1 requests. And the log shows fileField
is not received. How do I make the request correctly?
I found Opening an http/2 connection and POSTing form-data which says
In the Node HTTP2 docs it shows an example of how to do this.
but it seems to be only talking about separating const client = http2.connect(...)
and client.request
, not a form data example.
The minimum Node version I need to support is 20, and I'm happy to switch from form-data
if needed; I just had different errors with built-in FormData
but maybe I was doing something wrong there.
Upvotes: 2
Views: 52
Reputation: 170805
The solution was to replace
form.pipe(request);
request.end();
with
form.pipe(request);
form.on('end', () => { request.end(); });
Upvotes: 0