I am encountering an issue with file uploading in Express. Every time I send a request with multipart/form-data
, I receive a 400 bad request response with no error message, just an empty object. Currently, I am using busboy-body-parser for parsing multipart formdata requests. I also tried using express-fileupload and faced the same problem.
Below are my request methods:
get(endpoint) {
return this.request('GET', endpoint, null);
}
post(endpoint, body) {
return this.request('POST', endpoint, body);
}
postFile(endpoint, file) {
return this.request('POST', endpoint, file, contentTypes.file);
}
async request(method, endpoint, body, contentType=contentTypes.json) {
const { authToken } = this;
const endpointUrl = this.getEndpointUrl(endpoint);
const headers = new Headers();
if(authToken) {
headers.append(authTokenHeader, authToken);
}
headers.append('Accept', 'application/json, application/xml, text/plain, text/html, *.*');
headers.append('Content-Type', contentType);
const response = await fetch(endpointUrl, {
method: method,
headers: headers,
body: this._serializeRequestBody(body, contentType),
});
const result = await this._parseResponse(response);
if(!response.ok) {
if(response.status === 401) {
this.revokeAuth();
}
throw result || new Error('Unknown error (no error in server response)');
} else if(result && result.authToken) {
this.setAuthToken(result.authToken);
}
return result;
}
Here is _serializeRequestBody
and _parseResponse
:
_parseResponse(response) {
const contentType = response.headers.get('Content-Type').split(';')[0];
if(contentType === contentTypes.json) {
return response.json();
}
return response.text();
}
_serializeRequestBody(body, contentType) {
if(!body) return null;
switch(contentType) {
case contentTypes.json:
return JSON.stringify(body);
case contentTypes.file:
const formData = new FormData();
formData.append('file', body);
return formData;
}
return body;
}
And contentTypes
:
const contentTypes = {
json: 'application/json',
file: 'multipart/form-data',
};
My express middleware is as follows:
if(this._expressLoggingMiddleware) {
app.use(this._expressLoggingMiddleware);
}
if(this.isNotProductionEnv && this.isNotTestEnv) {
app.use(require('morgan')('dev'));
}
// Adds `res.success` and `res.fail` utility methods.
app.use(require('./utils/envelopeMiddleware')());
// Allow cross-origin requests if `config.cors` is `true`.
if(config.cors) app.use(require('cors')());
// Parse JSON and form request bodies.
app.use(busboyBodyParser()); // parses multipart form data (used for file uploads)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Lookup users by the JWT in their request header.
app.use(passportJWTMiddleware(passport, this.jwtSecret, jwtPayload =>
this.lookupUserfromAuthToken(jwtPayload).catch((error) => {
log.warn('Error while looking up user from JWT:', error);
return null;
})
));
// Serve files from `config.publicDir`.
if(config.publicDir) {
log.debug(`Hosting static files in "${config.publicDir}"`);
app.use(express.static(config.publicDir));
}
Request information can be found in Chrome's Dev Tools:
https://i.stack.imgur.com/y5Hqm.png
As well as the request payload:
https://i.stack.imgur.com/ORt70.png
And the response received: