Empty request body with POST using CORS with a nod

2019-08-14 16:14发布

I'm creating a simple Node app on OpenShift, using express (I'm just modifying the default example Node app of OpenShift). I want to have CORS support with it:

var cors = require('cors');
...

/**
 *  Initialize the server (express) and create the routes and register
 *  the handlers.
 */
self.initializeServer = function() {
    self.createRoutes();
    self.app = express();

    self.app.use(cors());
    self.app.use(express.json());

    //  Add handlers for the app (from the routes).
    for (var r in self.routes) {
        self.app.get(r, self.routes[r]);
    }

    self.app.post('/vote/', function (req, res) {
        // just echo back the request body
        res.json(req.body);
    });
};

If I send a request from my local machine, using curl it works fine:

C:\Users\Chin\Desktop>curl -H "Content-Type: application/json" -X POST -d "{\"username\":\"xyz\"}" https://bloodbrothers-chinhodado.rhcloud.com/vote/
{"username":"xyz"}

However, if I send the request from another site with a different domain using jQuery, the returned body is empty:

$.ajax({
    url: "https://bloodbrothers-chinhodado.rhcloud.com/vote/",
    type: "POST",
    crossDomain: true,
    data: JSON.stringify({"username": "xyz"}),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (response) {
        alert(response);
    },
    error: function (xhr, status) {
        alert("error");
    }
});

=> the server returns {}

I put a console.log() call inside the self.app.post() function and indeed when the request is coming from cross-domain, the body of the request is empty.

What did I do wrong here? The app is live so you can try the curl and ajax call yourself if you want to.

EDIT: In this case, if I make a CORS request, it does go into the self.app.post('/vote/', function (req, res) {} function (verified by putting in console.log() calls there). Does it mean that CORS is working well and the problem is not because of CORS?

1条回答
你好瞎i
2楼-- · 2019-08-14 16:47

I figured it out. It turns out that enabling CORS like I did didn't work since the content-type is JSON, which makes this request a "complex" request. From the docs:

A simple cross-site request is one that:

  • Only uses GET, HEAD or POST. If POST is used to send data to the server, the Content-Type of the data sent to the server with the HTTP POST request is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain.

  • Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

and from the npm cors package doc:

Enabling CORS Pre-Flight

Certain CORS requests are considered 'complex' and require an initial OPTIONS request (called the "pre-flight request"). An example of a 'complex' CORS request is one that uses an HTTP verb other than GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable pre-flighting, you must add a new OPTIONS handler for the route you want to support:

var express = require('express')
  , cors = require('cors')
  , app = express();

app.options('/products/:id', cors()); // enable pre-flight request for DELETE request 
app.del('/products/:id', cors(), function(req, res, next){
  res.json({msg: 'This is CORS-enabled for all origins!'});
});

So I made the changes and it's working well now.

查看更多
登录 后发表回答