文件上传请求全部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);