0

I'm trying to send a JSON object to an express server. This is my code for the client:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Express demo</title>
</head>
<body>
<button onclick="sendUrlEncoded()">Send an application/x-www-form-urlencoded POST request</button>
<button onclick="sendJson()">Send an application/json POST request</button>
<div id="response"></div>
<script>
function sendUrlEncoded() {
    var data = "text=stuff";
    var http = new XMLHttpRequest();
    http.open("POST", "http://127.0.0.1");
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.send(data);
}

function sendJson() {
    var data = {text:"stuff"};
    var http = new XMLHttpRequest();
    http.open("POST", "http://127.0.0.1");
    http.setRequestHeader("Content-Type", "application/json");
    http.send(JSON.stringify(data));
}

</script>
</body>
</html>

And this is the server:

var express = require("express");
var path = require("path");
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));

app.use(function(req, res, next) {
    console.log("Received request");
    console.log(req.headers);
    console.log(req.body);
    next();
});

app.get("/", function(req, res) {
    console.log("GET request");
    res.sendFile(path.join(__dirname + "/index.html"));
});

app.post("*", function(req, res) {
    console.log("Received post request");
    res.status=200;
});

var server = app.listen(3001, function() {console.log("Listening on port 3001")});

sendJson() was formerly "sendPost()" in the original version of this question. When the client sends a GET request or an XMLHttpRequest, the server always receives it. If it's a GET request or sent via sendUrlEncoded(), it contains the data in the body and calls the app.get() function successfully. However, with sendJson(), the server only gets the request in the general message handler. It doesn't call app.get(), and the request's body is {}. In addition, the header is not quite what I expect:

{
  host: 'xx.xxx.xxx.xxx:3001',
  connection: 'keep-alive',
  accept: '*/*',
  'access-control-request-method': 'POST',
  'access-control-request-headers': 'content-type',
  origin: 'http://192.168.0.102:3001',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
  'sec-fetch-mode': 'cors',
  referer: 'http://192.168.0.102:3001/',
  'accept-encoding': 'gzip, deflate',
  'accept-language': 'en-US,en;q=0.9'
}

Note: I replaced the real IP address with xx.xxx.xxx.xxx above. If you can help, I really appreciate it!

7
  • how are you calling sendPost? Commented Dec 11, 2020 at 10:07
  • I haven't heard of a sendPost method. Every tutorial I've seen says you use the XMLHttpRequest send method and specify "POST" as the method when you open it. Commented Dec 11, 2020 at 18:09
  • sendPost is you function ! :) the function within which the ajax object is instantiated - how you call it? Commented Dec 11, 2020 at 18:18
  • It's called on a button click, and I know that it's called successfully. I also know that express is receiving a POST request. However, the body is empty, and the header looks strange: Commented Dec 11, 2020 at 19:03
  • Instead of 'content-type': 'application/json', it has 'access-control-request-method': 'POST', 'access-control-request-headers': 'content-type'. Commented Dec 11, 2020 at 19:04

2 Answers 2

1

[Edited] You still need to remove the middleware before the app.get endpoint because it only adds some noise, and also end the request by sending the response back to the user, else the server will hang. In your previous code, you only set the response status to 200 but did not end the response with send or end The issue, most importantly is caused by the wildcard * that is used in both post requests. Just use two different endpoints for your requests.

See below.

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

// create application/json parser
// this will only handle application/json requests
// and will be passed to the route handler as middleware

var jsonParser = bodyParser.json()

// create application/x-www-form-urlencoded parser

var urlencodedParser = bodyParser.urlencoded({ extended: true })

// POST /urlencoded (fictitious endpoint) gets urlencoded bodies
// Test with your forms
app.post('/urlencoded', urlencodedParser, function (req, res) {
    res.send('welcome, ' + JSON.stringify(req.body))
})

// POST / gets JSON bodies
// Test with application/json

app.post('/', jsonParser, function (req, res) {
    console.log("Received post request for application/json type");
    console.log(req.body);
    res.send(JSON.stringify(req.body)).end();
})

app.listen(3001, function () {
    console.log("Listening on port 3001")
});

When I change the request to application/json, we get the expected result, which in this case is the request body echoed back.

enter image description here

And server logs:

Listening on port 3001
Received post request for application/json type
{ test: 'some stuff to show' }

You cannot set two different content-types for your requests. So you either send application/json type or you send x-www-form-urlencoded.

Is this what you are after?

Sign up to request clarification or add additional context in comments.

6 Comments

I removed the middleware and send the response back to the user, but that unfortunately didn't help. The server hanging was never the issue in the first place. The problem appears to be that either 1. AJAX isn't sending application/json requests properly, or 2. Express is receiving application/json requests improperly. Whether or not the middleware/sending the response back to the client is included or not, x-www-form-urlencoded requests still send and receive correctly. It's only application/json requests that don't, despite the code being virtually identical.
ah, ok I see now. Working on it and will update answer shortly
I made a little progress. When I try to send an application/json request, the following error lots in the browser console: Access to XMLHttpRequest at 'xx.xxx.xxx.xxx:3001' from origin '192.168.0.102:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. (index):26 POST xx.xxx.xxx.xxx:3001 net::ERR_FAILED sendJson @ (index):26 onclick @ (index):9 So it looks like the issue is upstream of express.
By accessing the program via the WAN IP rather than the local IP, this error resolves and express does receive the application/json POST request. However, the issue remains that the body is simply {} even though data is being send.
And this in turn was because I'd commented out app.use(bodyParser.json()). Adding that back in resolved the issue. Thanks for trying to help me out, rags21riches!
|
0

The issue was that I was accessing my server from a LAN IP when I should have been accessing it from a WAN IP. I had also commented out app.use(bodyParser.json()). The former issue prevented the request from sending properly from the client, and raised an error in the browser console. The latter error prevented express from receiving the json object in the body of the request.

I solved these problems as follows:

To enable CORS, I added:

var cors = require("cors");
app.use(cors());

To enable express to receive JSON from application/json POST requests, I added:

app.use(bodyParser.json());

For future n00bz like myself, I found this article helpful for explaining about CORS.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.