NodeJs:无法发送带有正文参数的 POST 请求:在服务器上时未定义 req.body.param

时间:2021-05-20 03:13:27

标签: javascript node.js express http

我有这个 server.js 代码:

const bodyParser = require('body-parser');
const cors = require('cors');
const morgan = require('morgan');


var express = require('express')
    , http = require('http')
    , https = require('https')
    , app = express();
app.use(morgan('combined'));
app.use(bodyParser.json());
app.use(cors());

http.createServer(app);
https.createServer({  }, app);

app.get('/', (req, res) => {
    res.json({message: "Home"})
});

app.get('/test', (req, res) => {
    res.json({message: "Testing..."})
});

app.post('/token', (req, res) => {
    var clientId = req.body.client_id;
    var clientSecret = req.body.client_secret;

    if (clientId === 'admin' && clientSecret === 'admin') {
        res.json({message: "Your token is 123456"});
    }
    else  {
        res.json({message: "Not allowed!"});
    }
})

app.listen(process.env.PORT || 8081);

还有这个 client.js 代码:

const http = require("http");
const querystring = require("querystring");

function getTestHome()  {
    const options = {
        method: "GET",
    }
    const token_endpoint = "http://localhost:8081/";
    const token_request = http.request(token_endpoint, options);
    token_request.once("error", err => {throw err});
    token_request.once("response",
        (token_stream) =>
            getFromStream(token_stream));
    token_request.end();
}

function getTestToken()  {
    const  parameters = {
        "grant_type": "client_credentials",
        "client_id": "admin",
        "client_secret": "admin"
    };

    const post_data = querystring.stringify(parameters);
    const options = {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        method: "POST",
        body: post_data
    }
    const token_endpoint = "http://localhost:8081/token";
    const token_request = http.request(token_endpoint, options);
    token_request.once("error", err => {throw err});
    token_request.once("response",
        (token_stream) =>
            getFromStream(token_stream));
    token_request.write(post_data);
    token_request.end();
}

function getFromStream(stream)  {
    let body = "";
    stream.on("data", piece => body += piece);
    stream.on("end", () => console.log(body));
}

getTestHome();  //{"message":"Home"}
getTestToken();  //{"message":"Not allowed!"}

我正在尝试向 /(不带参数的 GET 请求)和 /token(带有正文 JSON 数据的 POST 请求)发送请求。

GET 请求通过得很好,我得到了

{"message":"Home"}

留言。

然而,尽管我在 POST 请求中发送了正确的 client_idclient_secret,我还是得到了

{"message":"Not allowed!"}

回消息。

我尝试在 server.js 上使用调试器,我可以看到 req.body.client_idreq.body_client_secretundefined

enter image description here

我做错了什么,我该如何解决?

正确的输出应该是

{"message":"Home"}
{"message": "Your token is 123456"}

PS POST 请求在 Postman 中工作正常:

enter image description here

编辑

我想我明白了。

添加

app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

server.js 解决了它。

但我想知道是否有办法仅在 client.js 中解决它?如果我无法访问服务器代码?

1 个答案:

答案 0 :(得分:1)

就在您指向您的编辑时,you needed to add

app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

这是因为在您的客户端,您将数据发送为:

Content-type: application/x-www-form-urlencoded

这使得 express 需要额外的代码行来获取 req.body 中的数据(因为数据是如何发送的)。

另一方面,当您通过 Postman 进行操作时,您将内容类型显式设置为 JSON 原始数据,从而自动将请求标头设置为:

Content-type: application/json

Postman Content-type header

因此,您可以在客户端做的就是:将内容类型设置为 application/json,并将数据作为 JSON 发送:

function getTestToken() {
    const parameters = {
        "grant_type": "client_credentials",
        "client_id": "admin",
        "client_secret": "admin"
    };

    const options = {
        headers: { 'Content-Type': 'application/json' },
        method: "POST",
    }
    const token_endpoint = "http://localhost:8081/token";
    const token_request = http.request(token_endpoint, options);
    token_request.once("error", err => { throw err });
    token_request.once("response",
        (token_stream) =>
        getFromStream(token_stream));
    token_request.write(JSON.stringify(parameters));
    token_request.end();
}

您可以在客户端采用这种方法,而无需修改服务器的代码。使用这种方法,您还可以跳过查询字符串模块的导入。

相关问题