使用Fetch API和Multer上传文件时出现错误

12

我正在尝试使用Fetch API向Node.js服务器上传文件(如果与此有关,我正在使用GitHub的Polyfill:https://github.com/github/fetch)。

请求是这样完成的:

const data = new FormData();
data.append('file', file);
return fetch(this.concatToUrl(url), {
  method: 'post',
  headers: Object.assign({}, this.getHeaders(), {'Content-Type': 'multipart/form-data'}),
  body: data,
});

在服务器端,我有以下路由声明:

app.post('/media', upload.single('file'), mediaRoutes.postMedia);

尝试像这样获取文件:

exports.postMedia = function(req, res) {
  console.log('req.file', req.file, req.files, req.body);
  return res.sendStatus(200);
}

但是req.file没有被填充。

同时我从express端得到了这个错误:

Error: Multipart: Boundary not found
[2]     at new Multipart (/Users/jmanzano/Development/web/test/node_modules/busboy/lib/types/multipart.js:58:11)
[2]     at Multipart (/Users/jmanzano/Development/web/test/node_modules/busboy/lib/types/multipart.js:26:12)
[2]     at Busboy.parseHeaders (/Users/jmanzano/Development/web/test/node_modules/busboy/lib/main.js:64:22)
[2]     at new Busboy (/Users/jmanzano/Development/web/test/node_modules/busboy/lib/main.js:21:10)
[2]     at multerMiddleware (/Users/jmanzano/Development/web/test/node_modules/multer/lib/make-middleware.js:32:16)
[2]     at Layer.handle [as handle_request] (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/layer.js:95:5)
[2]     at next (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/route.js:131:13)
[2]     at Route.dispatch (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/route.js:112:3)
[2]     at Layer.handle [as handle_request] (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/layer.js:95:5)
[2]     at /Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:277:22
[2]     at Function.process_params (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:330:12)
[2]     at next (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:271:10)
[2]     at cors (/Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:178:7)
[2]     at /Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:228:17
[2]     at originCallback (/Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:217:15)
[2]     at /Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:222:13
[2]     at optionsCallback (/Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:203:9)
[2]     at /Users/jmanzano/Development/web/test/node_modules/cors/lib/index.js:208:7
[2]     at Layer.handle [as handle_request] (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/layer.js:95:5)
[2]     at trim_prefix (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:312:13)
[2]     at /Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:280:7
[2]     at Function.process_params (/Users/jmanzano/Development/web/test/node_modules/express/lib/router/index.js:330:12)

这是通过中间件进行的配置:

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(expressValidator());
app.use(logger('dev'));
app.use(cookieParser());
app.use(methodOverride());
app.use(passport.initialize());
app.use(passport.session());
app.set('JWTSuperSecret', jwtConfig.secret);

if (process.env.NODE_ENV !== 'production') {
  app.use(cors());
}

另外,这在POSTMAN中能够正常工作。因此,我认为我在请求方面做错了什么。

谢谢!

2个回答

17

对于那些在使用 Postman 时遇到错误的人,请确保在头部信息中不要指定 content-type


11

不需要指定头信息{Content-Type': 'multipart/form-data'},浏览器会自己替换。

但是如果您暴露它,那么在请求负载(Request Payload)之前,在请求头(Request Headers)中未指定boundary,这会导致服务器端出错。

如果您打开浏览器控制台并查看标头,就会看到它。

所以,只需:

fetch(this.concatToUrl(url), {
  method: 'post',
  body: data,
});

或者,如果您需要自定义标题,则可以像这样添加它们:

var headers = Object.assign({},
                            {'content-type': 'application/json'},
                            this.getHeaders(), 
                            {'Content-Type': 'multipart/form-data'}
);

   // Removal should be case insensitive, or in any case, the header will be included:


Object.keys(headers)
      .forEach( function(k) { 
         if (k.toLowerCase()==='content-type') delete headers[k] 
      })

const data = new FormData();
data.append('file', file);
return fetch(this.concatToUrl(url), {
  method: 'post',
  headers: headers,
  body: data,
});

这种方法的问题在于我必须设置更多的自定义标头(例如允许JWT身份验证)。我该如何实现? - Javier Manzano
1
只需从头列表中提取“content-type”属性即可。请参见更新。 - stdob--

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接