【问题标题】:handle multipart/formdata, application/json, and text/plain in single express handler?在单个 express 处理程序中处理 multipart/formdata、application/json 和 text/plain?
【发布时间】:2018-04-11 21:09:45
【问题描述】:

我有一个快速演示服务器,它回显客户端向它发送的内容。

在学习活动中使用,客户端将使用 fetch API 进行 POST,例如:

fetch('http://localhost:5000/', {
  method: 'POST',
  body: JSON.stringify({ lab: 'fetch', status: 'fun' }),
  headers: messageHeaders
})

数据的body 将是字符串、JSON 或FormData

我对 express 不是很熟悉,但我希望只有一条路线可以处理所有三种 body 类型。目前我无法弄清楚如何做到这一点。

我从 this SO post 开始,但该解决方案不适用于我的情况 - 我认为 res.format API 不允许我访问请求的正文,它似乎也不适用于多部分表单数据。

相反,我默认在潜在的中间件黑客配置中使用 body-parsermulter 包:

// if client POST body is a string, parse as text
app.post('/', bodyParser.text(), (req, res, next) => {
  const contentType = req.get('content-type');
  if (!contentType.includes('text/plain')) {
    return next();
  }
  res.write(JSON.stringify(req.headers, null, 2))
  res.write('\n\n')
  res.write(req.body)
  res.end()
});

// if client POST body is JSON, parse as JSON
app.post('/', bodyParser.json(), (req, res, next) => {
  const contentType = req.get('content-type');
  if (!contentType.includes('application/json')) {
    return next();
  }
  res.write(JSON.stringify(req.headers, null, 2))
  res.write('\n\n')
  res.write(JSON.stringify(req.body, null, 2))
  res.end()
});

// if client POST body is FormData, parse as form-data
app.post('/', upload.fields([]), (req, res, next) => {
  const contentType = req.get('content-type');
  if (!contentType.includes('multipart/form-data')) {
    return next();
  }
  res.write(JSON.stringify(req.headers, null, 2))
  res.write('\n\n')
  res.write(JSON.stringify(req.body, null, 2))
  res.end()
});

是否有更标准或“更好”的模式来实现此功能?也许我只需要编写一个处理程序?

【问题讨论】:

  • 我觉得你在那里做的很好,它给你带来了什么问题?
  • 没有错误。只是不熟悉 express & 似乎单个处理程序将是一个更好或更规范的模式。我认为服务器框架可以在单个路由中解析不同类型的输入,但我没有找到任何适用于这种情况的示例代码。如果它是合法的,那么我很乐意接受。
  • 您可以通过创建bodyParser 等实例,然后附加到它的下一个事件,在一条路线中完成。例如。 var bodyparser_text = bodyParser.text(); 然后在路线内,.. if (somecondition) bodyparser_text(req, res, function (req, res) { /*rest of code*/}),或类似的东西.. 未测试..
  • 嗯。我尝试了您的建议(至少我对您的建议的错误解释)没有成功。我不认为bodyParser/etc API 真的支持吗?看起来bodyParser 只需要一个options 配置对象,并且不直接与其中的回调等一起使用。我想我知道我要做什么了 - 请参阅我建议的答案
  • 首先你应该做app.use(bodyParser.json()); 然后在你的路线上app.post('/notes', multer.array("files", 5), (req, res)=> {});

标签: javascript node.js express


【解决方案1】:

一个更简洁的解决方案可能是将中间件作为数组传递给特定的路由,它最终会被解析。

app.post('/notes', [urlencodedParser, multiPart.array("files", 5)], (req, res)=> {
   //do what you want
   console.log(req.files);// to get the files
   console.log(req.body);// to get the body 
})

不过,您可以使用app.use(middleware:parser);,但请注意,这样一来,将为您的应用程序中 express 处理的所有路由调用中间件函数。

所以我认为在需要这种动力的特定路线上处理它更整洁,并且可能具有更好的性能。

【讨论】:

  • 是的,这更有意义,尤其是在我有其他不需要访问所有三个解析器的路由的情况下。谢谢
【解决方案2】:

我想我只是误解了表达概念(这可能是一个糟糕的问题)。

我假设我必须在我的路由中使用这些正文解析函数(multer/upload.fieldsbodyParser)作为回调,例如:

router.post('/', /* parsing callback */, function(req, res) {
  // ..
});

或者我可以在路由中使用解析器,例如:

router.post('/', function(req, res) {
  if (condition) {
     /* parserA */
  } else {
     /* parserB */
  }
});

对于前者,我不确定如何在单个路由中为不同的内容类型使用多个解析器,而对于后者,我实际上找不到直接使用解析器的 API 签名(这仍然是一个对我来说有点奇怪,也许我搜索得不够好?)。

但在任何情况下,我都能够通过使用路径之外的所有解析器将我的代码压缩成一条更清晰的路径。最终代码看起来更像:

const upload = multer();
app.use(upload.fields([]));
app.use(bodyParser.json());
app.use(bodyParser.text());

app.post('/', (req, res) => {

  res.write(JSON.stringify(req.headers, null, 2))
  res.write('\n\n')

  const contentType = req.get('content-type');

  if (contentType.includes('text/plain')) {
    res.write(req.body)
  }

  if (contentType.includes('application/json') ||
      contentType.includes('multipart/form-data')) {
    res.write(JSON.stringify(req.body, null, 2))
  }

  res.end()

});

在这里,对于每个请求,我基本上在应用程序顶部调用了所有三种类型的解析器(字符串、json、formdata),并且只有适当的解析器才会真正修改req.body财产。因此,在路由本身中,我可以根据内容类型发回数据,并进行适当的解析。

编辑:@Keith 指出这种实现可能性能较差,因为每个请求都会调用解析器,因此它不一定是“更好”的解决方案。

【讨论】:

  • 在某种程度上,这就是你通常做事的方式。但是当你在路由上附加你的解析器时,我假设你是出于性能原因这样做的。使用 express 如果您知道路由不需要中间件,则可以将其省略,然后将其包含在其他需要的路由中。现在,每个请求都将进行检查,然后传递到下一个中​​间件,直到有一个处理它为止。不太确定为什么直接调用中间件的建议不起作用。所有中间件都只是(req, res, next) 形式的函数回调
  • 啊,我明白了,这是一个很好的观点。我不知道解析器是如何实现的,但我希望它们被包装在一个简单的条件检查中,如果它们不应该解析请求,请调用 next(),这样只有正确的解析器才能真正进行重要的计算。感谢您的输入!如果值得您用更明确的代码提交第二个答案,我很乐意测试并接受您建议的实现。但我不能让它自己工作。无论哪种方式都无需担心。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 2018-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多