文件上传请求全部return 400个状态码
File upload requests all return 400 status codes
我正在尝试使用 Express 进行文件上传,但我发送的每个 multipart/form-data
请求都会收到 400 错误请求响应,并且没有错误。只是一个空对象。我目前正在使用 busboy-body-parser for parsing multipart formdata requests, but I also tried express-fileupload 和 运行 解决完全相同的问题。
以下是我的请求方式:
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;
}
这里是 _serializeRequestBody
和 _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;
}
和contentTypes
:
const contentTypes = {
json: 'application/json',
file: 'multipart/form-data',
};
还有我的 express 中间件:
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));
}
这是Chrome开发工具
中的请求信息
请求负载:
响应:
答案最终是:不要手动将 Content-Type
header 设置为 multipart/form-data
因为如果你让浏览器为你做,它也会附加内容类型需要 boundary
值。
所以为了修复我的代码,我只需要在发送 JSON:
时明确设置 Content-Type
header
if(contentType === contentTypes.json) headers.append('Content-Type', contentType);
我正在尝试使用 Express 进行文件上传,但我发送的每个 multipart/form-data
请求都会收到 400 错误请求响应,并且没有错误。只是一个空对象。我目前正在使用 busboy-body-parser for parsing multipart formdata requests, but I also tried express-fileupload 和 运行 解决完全相同的问题。
以下是我的请求方式:
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;
}
这里是 _serializeRequestBody
和 _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;
}
和contentTypes
:
const contentTypes = {
json: 'application/json',
file: 'multipart/form-data',
};
还有我的 express 中间件:
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));
}
这是Chrome开发工具
中的请求信息请求负载:
响应:
答案最终是:不要手动将 Content-Type
header 设置为 multipart/form-data
因为如果你让浏览器为你做,它也会附加内容类型需要 boundary
值。
所以为了修复我的代码,我只需要在发送 JSON:
时明确设置Content-Type
header
if(contentType === contentTypes.json) headers.append('Content-Type', contentType);