首页 > 解决方案 > NodeJS'express.use'调用顺序不一致

问题描述

版本: express@4.16.4 , body-parser@1.18.3

在 AWS EC2 上使用 nodejs 设置进行测试,并在本地机器上直接运行一个 html 网页。我注意到中间件/路由器的调用序列中存在不一致的行为。在下面的 html 中,GET 请求可以返回 json {from:'nodejs'}。但是,POST 请求直接跳转到方法Invalid URL

更多测试场景:

  1. 完全删除第二个app.useGET 和 POST 请求都可以返回 json {from:'nodejs'},并且 POST 请求req.body输出正确的数据{from:'html'}
  2. 删除xhr.setRequestHeader("Content-Type", "application/json");GET 和 POST 请求都可以返回 json {from:'nodejs'},但req.body预期为空白

html代码:

<!DOCTYPE html>
<html>
<body>

<button type="button" onclick="get()">GET</button>
<button type="button" onclick="post()">POST</button>
<p id="output"></p>

<script>
function get() {

    var xhr = new XMLHttpRequest();
    xhr.open("GET", 'http://54.169.54.221:8000/get', true);

    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var json = JSON.parse(xhr.responseText);
            console.log("Server Responded:" + JSON.stringify(json));
            document.getElementById("output").innerHTML = JSON.stringify(json);
        }
    };
    xhr.send();
}

function post() {

    var json = '{"from":"html"}';
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'http://54.169.54.221:8000/post', true);

    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            var json = JSON.parse(xhr.responseText);
            console.log("Server Responded:" + JSON.stringify(json));
            document.getElementById("output").innerHTML = JSON.stringify(json);
        }
    };
    xhr.send(json);
}
</script> 

</body>
</html> 

服务器代码:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

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

app.use(function(req, res, next) {
    console.log( 'global pre-process middleware invoked' );
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'content-type');
    next();
});

app.get('/get', function (req, res, next) {
    try {
        var json = {from:'nodejs'};
        console.log( JSON.stringify(json,null,'    ') );
        res.end( JSON.stringify(json,null,'    ') );
    } catch (e) {
        next(e);
    }
});

app.post('/post', function (req, res, next) {
    try {
        console.log(JSON.stringify(req.body));

        var json = {from:'nodejs'};
        console.log( JSON.stringify(json,null,'    ') );
        res.end( JSON.stringify(json,null,'    ') );
    } catch (e) {
        next(e);
    }
});

app.use(function(req, res, next) {
    console.log('Invalid URL');
});

var server = app.listen(8000, function () {
    var host = server.address().address;
    var port = server.address().port;
    console.log('Listening at http://%s:%s', host, port);
});

标签: javascripthtmlnode.js

解决方案


请更新服务器端代码,因为在客户端您使用的是 Content-type: application/json。

xhr.setRequestHeader("Content-Type", "application/json");

要解决此问题,请同时在节点服务器代码中指定内容类型。

res.setHeader("Content-Type", "application/json")

结果,您的节点服务器文件将如下所示

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

app.use(bodyParser.json());

app.use(function(req, res, next) {
    console.log( 'global pre-process middleware invoked' );
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader("Content-Type", "application/json")
    next();
});

app.post('/echo', function (req, res, next) {
    try {
        var body = JSON.stringify(req.body);
        console.log('/echo: ' + body);
        res.send(body);
    } catch (e) {
        next(e);
    }
});

app.use(function(req, res) {
    console.log('Invalid URL');
});

var server = app.listen(8000, function () {
    var host = server.address().address;
    var port = server.address().port;
    console.log('Listening at http://%s:%s', host, port);
});


推荐阅读