Node.js(带有express和bodyParser):无法从POST请求获取表单数据

50

我似乎无法获取发送到我的 Node.js 服务器的 POST 请求的表单数据。下面是服务器代码和 POST 请求(在 Chrome 中使用 Postman 发送):

POST 请求

POST /api/login HTTP/1.1
Host: localhost:8080
Cache-Control: no-cache

----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="userName"

jem
----WebKitFormBoundaryE19zNvXGzXaLvS5C

NodeJS 服务器代码

var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(bodyParser());

app.all('/*', function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type,accept,access_token,X-Requested-With');
    next();
});

var port = process.env.PORT || 8080;        // set our port

var router = express.Router();              // get an instance of the express Router

router.get('/', function(req, res) {

    res.json({ message: 'I am groot!' });   
});

// Login
router.route('/login')

    .post(function(req, res){

        console.log('Auth request recieved');

        // Get the user name
        var user = req.body.userName;

        var aToken = getToken(user);

        res.json({

            'token':'a_token'
        });
    });

app.use('/api', router);

app.listen(port);

登录方法尝试获取req.body.userName,但是req.body始终为空。 我在SO上看到其他描述此行为的情况,但是相关答案都不适用于这里。

感谢您的帮助。


3
问题在于请求的正文是一个“multipart”消息,并且“body-parser”模块不支持解析该格式的数据。它的自述文件中的第二段提供了其他可以使用的模块的建议。 - Jonathan Lonowski
2
或者,如果POST请求中的数据不需要multipart,则可以将其作为x-www-form-urlencoded发送。这是bodyParser.urlencoded()解析的格式。 - Jonathan Lonowski
确实,谢谢指出。我对HTTP的了解有限,所以不知道form-urlencoded。这样,我的node.js就可以正确处理来自小型angular前端的post请求。感谢您的帮助! - Jem
7个回答

45

通常情况下,一个 Express 应用需要指定适当的body-parser 中间件才能使req.body包含请求体。

[已编辑]

  1. 如果你需要解析url-encoded(非多部分)表单数据以及 JSON,请尝试添加:

    // Put this statement near the top of your module
    var bodyParser = require('body-parser');
    
    
    // Put these statements before you define any routes.
    app.use(bodyParser.urlencoded());
    app.use(bodyParser.json());
    

    首先,您需要将body-parser添加到您的package.json文件的dependencies属性中,然后执行npm update

  2. 要处理多部分表单数据,bodyParser.urlencoded()主体解析器将无法工作。请参阅此处的建议模块以解析多部分主体。


3
OPжҳҫзӨәжӯЈеңЁдҪҝз”Ёbody-parserжЁЎеқ—пјҢ然иҖҢиҜҘжЁЎеқ—дёҚж”ҜжҢҒmultipartи§ЈжһҗгҖӮ - Jonathan Lonowski
1
我已经编辑了我的答案,包括建议的多部分表单解析模块的参考。感谢@Jonathan提供的参考。 - cybersam
谢谢你的帮助。事实上,我一直在发送表单数据,不知道服务器能够接受 URL 编码的数据。现在用后者可以正常工作了。 - Jem
将会审视 URL 编码和表单数据的优缺点。再次感谢! - Jem

16

我按照这个https://www.tutorialspoint.com/expressjs/expressjs_form_data.htm进行了操作。

var bodyParser = require('body-parser');
var multer = require('multer');
var forms = multer();

// apply them

app.use(bodyParser.json());
app.use(forms.array()); 
app.use(bodyParser.urlencoded({ extended: true }));

// how to use

router.post('/', function(req, res) {
    console.log(req.body);
    console.log('received the widget request');
});

8
当我在代码中使用console.log(req.body)后,输出的结果是{} - Zackattack

7
为了处理支持文件上传的 multipart/form-data 请求,您需要使用 multer 模块。请使用 multer 中间件。multer npm 链接

6
在 multer 处理上传之前如何从 post 请求中读取 body? - Camilo Ortegón
1
@CamiloOrtegón,你在上面的评论中找到了你问题的解决方案吗? - Geek Guy
我也遇到同样的问题,需要分别处理文本数据和上传。 - Greggory Wiley

6
针对 JSON 数据,建议使用 body-parser 解析。
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))

你还应该在请求头中发送Content-Typeapplication/json

  • 对于普通表单或包含文件的多部分表单,请使用body-parser + multer
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))
app.use(multer().array())

在这种情况下,您不应发送Content-Type: application/json。您应该什么都不发送,或者如果表单中有文件,可以发送Content-Type: multipart/form-data

  • 在Postman中,您不应手动发送Content-Type: multipart/form-data。否则,您将收到一个错误(未找到边界)。(它会自动添加此内容)。

3

请确保按照以下顺序进行设置:

app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true }));

首先要使用bodyParser.json()


1
最好能够解释一下为什么。 - Neithan Max
Carles Alcolea,这两个中间件将按顺序执行。我还没有查看源代码,但我敢打赌,如果主体是JSON,则首先使用urlencode,它可能会发送一个错误回来,而不是跳过并调用下一个中间件。这可能就是JSON模块的作用,如果不是JSON,则跳过(调用next()),而不是发送错误并调用下一个中间件。 - Aecio Levy
我的意思是在编辑您的答案时为任何阅读它的人添加非常必要的解释。当我们证明我们的答案时,它更具有教育性和清晰度。这也有助于确保我们对答案的确定性;P - Neithan Max

1

确保你没有使用multipart/form-data作为enctype,因为body parser不支持它。 在定义任何路由之前,请使用以下行。

app.use(bodyParser.urlencoded()); app.use(bodyParser.json());


0
我发现在我的情况下,我没有使用HTML输入标签的“name”属性。我通过更改以下内容来解决它:

这个

<input id="first_name" />

<input id="first_name" name="first_name" />

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