0

Version: express@4.16.4 , body-parser@1.18.3

Tested with nodejs setup on AWS EC2, and a html webpage run directly on local machine. I notice that there is an inconsistent behavior in the calling sequence of middleware/router. In following html, the GET request is ok returning json {from:'nodejs'} . However, POST request jumps directly to method Invalid URL.

More test scenarios:

  1. Entirely remove the second app.use both GET and POST requests are ok returning json {from:'nodejs'} , and POST request req.body output the correct data {from:'html'}
  2. Removing xhr.setRequestHeader("Content-Type", "application/json"); both GET and POST requests are ok returning json {from:'nodejs'} , but req.body is blank which is expected

html code:

<!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> 

Server code:

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);
});

Konsy
  • 49
  • 1
  • 8
  • Take this with a grain of salt, but `.use()` is used to include middleware, i.e. the function runs before `.get()` or `.post()`, regardless of the order. –  Jan 26 '19 at 14:51
  • @ChrisG that's completely wrong. First of all `.get` and `.post` are also middlewares, but only called if the method matches. And all middlewares are called in the order they have been attached. – t.niese Jan 26 '19 at 16:35
  • Is my assumption correct that you do a cross origin request, and that the website code is not delivered on port `8000` but e.g. `80`? – t.niese Jan 26 '19 at 16:39
  • I can't reproduce the problem. Which version of `express.js` have you installed? – t.niese Jan 26 '19 at 17:02
  • @t.niese `express.js` version is 3.5.2. The website code is stored and run on local machine, only the server code is hosted on AWS EC2. Tried some suggested answers below, still not working... – Konsy Jan 27 '19 at 04:03
  • @t.niese correction, is `express@4.16.4` , mind sharing your version? wanted to test it – Konsy Jan 27 '19 at 04:25

3 Answers3

0

Please update server-side code because on client-side you are using Content-type: application/json.

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

To fixing this issue please specify content-type in node server code as well.

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

As a result your node server file will look like this

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);
});

Mubeen Khan
  • 997
  • 1
  • 10
  • 11
0

The error is caused because u didn't really validate, anything in ur validate url in ur middleware function

 app.use(function(req, res, next) {
   If(success with url) {
      next();
   } else {
      console.log('invalid url');
   }
 });
elraphty
  • 630
  • 6
  • 13
  • The idea of placing a `app.use(function(req, res/*, next* /) { ... }`) after all other routers is, that it is called if non of them matched. So there is no need to test for any url, because if it is called then it is clear, then non previous (valid url) was called. – t.niese Jan 26 '19 at 16:33
0

It is the behavior of CORS Access-Control-Allow-Origin. The browser before sending a POST request with a Content-Type other than:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

sends an OPTIONS request, asking whether the server can accept such a request. In my server code this OPTIONS request is not handled, thus, intercepted by 'Invalid URL'

More information on OPTIONS request and CORS

Konsy
  • 49
  • 1
  • 8