我该如何在Express js中轻松获取表单数据?

97

我有一个POST请求,其中包含非常简单和少量的表单数据。我最容易获取它的方法是什么?

许多教程/文章等等都谈到了bodyParser,但这已不再与Express捆绑在一起。其他地方(博客等)建议直接使用urlencoded,但现在这也不可用。

试图找到有关这些框架或技术的准确信息正在困扰我。

请问有人可以告诉我在Express中获取已发布表单数据的推荐(最新)方法是什么?


4
不应该对这个进行负投票。实际上,没有简单的文档来解释如何读取单个POST参数。已接受的解决方案使用了一个过时的包。 - Jeremy
4
我认为被接受的解决方案并没有使用过时的包。Mritunjay所提到的包名中有一个连字符,我相信它与易受攻击的“bodyparser”中间件不同。我认为一些博客文章警告原始的“bodyparser”在其中提到了它。这就是为什么我同意它不应该被投票降低(即不显示任何研究努力),因为我搜寻了很长时间的解决方案,但问题是有太多旧的和混乱的信息,让我感到很困惑。 - Dave Pile
1
感谢您的澄清,我没有意识到body-parser和bodyParser包之间存在差异。这种微妙之处是这个问题成为一个合适问题的原因之一。 - Jeremy
7个回答

88

你应该通过npm-install安装body-parser。现在它作为单独的中间件提供。

之后在你的app.js文件中添加以下代码:

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
// in latest body-parser use like below.
app.use(bodyParser.urlencoded({ extended: true }));

它将post请求解析为一个object。您可以在req.body中获取您的变量。

在您的post请求处理程序中。

app.post('/post',function(request,response){
   console.log(request.body) //you will get your data in this as object.
})

编辑 1

上面的答案是针对特定问题提出的,OP正在寻找已经不再是express的一部分的bodyParser(已弃用)。

由于问题的标题非常通用,而答案并不包括所有form-data的方面,因此我将把@StLia的答案作为编辑。

Body-Parser 自述文件

这不处理多部分主体,因为它们通常很复杂且通常很大。 对于多部分主体,您可能会对以下模块感兴趣:


15
在 Express 4 中,现在使用以下代码: app.use(bodyParser.urlencoded({ extended: true })); 该代码用于解析 URL 编码的请求体,并将其存储为对象。其中,extended 属性设置为 true 表示可以解析任何数据类型,包括字符串、数组和嵌套对象。 - Jeff
由于后续版本的body-parser没有默认值,因此您需要提供扩展选项。 - Phil
3
是的,但它不能与包含文件的FormData()一起使用。@stlia的回答很好。 - Alexander Kim
3
在 Express 4.16 中,body-parser 已经内置。你可以使用 app.use(express.urlencoded({ extended: true })) - Moritz
也许您可以编辑答案,包括从v4.16+版本开始这些内容已经与Express捆绑在一起。 - sayandcode

40

您可以使用 express-formidable 模块来实现这一点。 通过以下命令安装 'express-formidable'

npm install express-formidable

简单示例如下

const express = require('express');
const formidable = require('express-formidable');
 
var app = express();
 
app.use(formidable());
 
app.post('/upload', (req, res) => {
  //req.fields contains non-file fields 
  //req.files contains files 
  res.send(JSON.stringify(req.fields));
});

点击此处以获取更多描述


1
对我也起作用了。接受的答案在使用带有文件的 FormData() 时没有起作用。 - DileepNimantha
尝试使用Express Formidable。注意到一个问题。如果我们将字段的值作为数字传递,Formidable会将其转换为字符串。 - Jinu Joseph Daniel

27

body-parser的README中:

由于其复杂且通常较大的特性,它不处理多部分体。

以上将适用于x-www-form-urlencodedjson,但不会使用任何multipartform-data也是具有标题multipart/form-datamultipart

对于form-data,您最好使用express-formidable


6

正如这个StackOverflow回答所述:

Express 4.16+已经实现了他们自己的版本的body-parser,因此您不需要将其添加到项目中。您可以在express中本地运行它

app.use(express.json()); // Used to parse JSON bodies
app.use(express.urlencoded()); // Parse URL-encoded bodies using query-string library
// or
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies using qs library

参见: query-string vs qs


5
我注意到@HubballiHuli的答案是使用名为express-formidable的包。 您不需要使用这个不必要的包,它只提供了一个(很小的)代码文件。 相反,您可以自己完成它(现在删除依赖关系)。
这是formidableMiddleware文件:
'use strict';

const formidable = require('formidable');

function parse(opts, events) {
  return (req, res, next) => {
    if (req.express_formidable && req.express_formidable.parsed) {
      next();
      return;
    }

    const form = new formidable.IncomingForm();
    Object.assign(form, opts);

    let manageOnError = false;
    if (events) {
      events.forEach((e) => {
        manageOnError = manageOnError || e.event === 'error';
        form.on(e.event, (...parameters) => { e.action(req, res, next, ...parameters); });
      });
    }

    if (!manageOnError) {
      form.on('error', (err) => {
        next(err);
      });
    }

    form.parse(req, (err, fields, files) => {
      if (err) {
        next(err);
        return;
      }

      Object.assign(req, { fields, files, express_formidable: { parsed: true } });
      next();
    });
  };
}

module.exports = parse;
exports.parse = parse;

现在来介绍如何使用它:

const express = require('express');
const formidableMiddleware = require('./formidableMiddleware.js');

var app = express();

app.use(formidableMiddleware());

app.post('/upload', (req, res) => {
  //req.fields contains non-file fields 
  //req.files contains files 
  res.send(JSON.stringify(req.fields));
});

我之前写过一篇关于不必要软件包的文章,说明了为什么应该避免使用它们: https://medium.com/@alexjamesdunlop/unnecessary-packages-b3623219d86


5
除了使用 "formidable" 的解决方案外,还有另一个模块自 2019 年以来一直在我的最近项目中使用。该模块是 express-form-data,可以在服务器文件中轻松声明如下:
const express = require('express');
const formData = require('express-form-data');

app.use(formData.parse());

app.post('/image-upload', (req, res) => {
  console.log(req.files);
})

...

例如,在上传图片的情况下,req.files将提供处理文件所需的所有相关数据,如路径、大小、文件名等。


3
如果您想将 formidableMiddleware 仅应用于一个 API 路由而不是全局应用,可以按以下方式传递该值。
如果您想要混合使用不同的标头传递到其他 API 的 API,但又不想应用 formidableMiddleware API,则此方法会很有用。
const express = require('express');
const formidable = require('express-formidable');

var app = express();

app.post('/mypath', formidableMiddleware(), (req, res) => {
  // rest of the code
})

1
这对我起作用了。在我的情况下,我使用req.fields访问表单数据字段。 - henrykodev

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