Node.JS returns a 404 on interrogation of an endpoint that actually exists

Viewed 607

I have a web application, started by a previous company, written in Angular.JS.
The application exposes a request towards the back-end (written in Node.JS+Express) to gather some data required to fill a table.
Specifically, this is the request that the application sends everytime the user enters in the page that holds the table (The config variable holds the access token).

return $http.get(API + '/api/myPath/for/Having/Data', config).then(handleSuccess, handleError);

handleSuccess and handleError are so defined

        handleSuccess: function (res) {
            debugger;
            var deferred = $q.defer();
            res.data.success ? deferred.resolve(res.data) : deferred.reject(res.data.message);
            return deferred.promise;
        },

        handleError: function (error) {
            return {
                success: false,
                message: error
            };
        }

In my back-end I've put an a listener to whatever gets called with the "/api" prefix, like this

app.use('/api', authorization.validateToken);

And another listener, that should work only if there is no match (written at the very end of the file that handles all the general inquiries of the app)

app.all('*', (req, res) => {
    console.log('Hi, Stack Overflow!');
    res.send({
        success: false,
        status: 404,
        message: 'Invalid Uri Resource'
    });
});

And, lastly, this is the endpoint that should get called in the back-end from Angular.js

app.get('/api/myPath/for/Having/Data', something.somethingToCall);

Here's the funny part: for a reason that I still have to understand, Angular.JS calls that endpoint twice, resulting in one failing procedure (404) and another one that goes smoothly (200).
The operation flow should be like this: Angular calls the back-end --> Node checks the validity of the token --> executes operation if everything goes okay.
The operation is called twice (seen thanks to the Visual Studio Code debugger and Chrome's Network Monitor) and, even though the token's validation process is correctly executed everytime, the first time the next() function will hold the app.all() listener.
Also,even before I start debugging the first request that is sent out, the JavaScript console on Google Chrome warns me that there has been an error such as like "Cannot read property 'data' of undefined", meaning that the request gets executed twice with the first time returning a 404.

exports.validateToken = (req, res, next) => {
    console.log(`check user here`);
    // next();
    var token =  //I take the token 
    console.log(token);
    if (token) {
        jwt.verify(token, require('../../secret'), (err, decoded) => {
            if (err) {
                res.send({
                    success: false,
                    status: 500,
                    tokenExpired: true,
                    message: "Effettua nuovamente l'accesso"
                });
            } else {
                req.decoded = decoded;
                next();
            }
        });
    } else {
        res.send({
            success: false,
            status: 406, // Fprbidden
            message: 'User not Authenticated'
        });
    }
};

Does anybody know how to help me somehow? EDIT: this is an example of how Chrome's sees both requests. The screenshot, in particular, refers to the first one that gets called and produces the 404

The CORS is handled in the back-end like this

app.use(function (req, res, next) {

    if (req.headers.origin && (req.headers.origin.match("http:\/\/somewebsite.com.*") || req.headers.origin.match("http:\/\/localhost:8010") )) {
        res.header("Access-Control-Allow-Origin", req.headers.origin);
    }

    next();
});

Also, I'm adding the endpoint that needs to be called. This also exploits MongoDB + Mongoose for querying the DataBase and return stuff to the front-end. The parameters that I'm passing are pageSize (how many elements per page) and the current page number

exports.getAds = (req, res) => {

  var criteria = req.body || {};
  var pageSize = criteria['pageSize'] ? Number(criteria['pageSize']) : undefined;
  var pageNumber = criteria['pageNumber'] ? Number(criteria['pageNumber']) : undefined;

  var sort = criteria.sort || { createdAt: 'desc' };

  if (criteria.customerName) criteria.customerName = { $regex: `.*${criteria.customerName}.*`, $options: 'i' };
  if (criteria.spentEuros) criteria.spentEuros.$gte = criteria.spentEuros;
  if (criteria.referralMail) criteria.referralMail = { $regex: `.*${criteria.referralMail}.*`, $options: 'i' };


  console.log(criteria);

  var columns = "customerName duration spentEuros";

  if (pageSize && pageNumber) {
    Adv.paginate(criteria, {
      page: pageNumber,
      limit: pageSize,
      select: columns,
      sort: sort
    }, function (err, result) {
      if (!err) res.status(200).send({ success: true, data: result });
      else res.status(500).send({ success: false, message: err });
    });
  } else {
    Adv.find(criteria)
      .select(columns)
      .sort(sort)
      .exec(function (err, result) {
        if (!err) res.status(200).send({ success: true, data: result });
        else res.status(500).send({ success: false, message: err });
      });
  }

};

EDIT2: Solution to the question: adding an app.options listener in the back-end (as pointed out by @slebetman), alongside with the already existing app.get one, solved the issue

The first endpoint call that produces the 404

1 Answers

Here's the funny part: for a reason that I still have to understand, Angular.JS calls that endpoint twice...

That sounds a lot like the browser sending a CORS preflight OPTIONS request, followed by a GET. Check the HTTP verb being used, and be sure you're handling OPTIONS (not just GET) if you need to support CORS on your endpoint. (If you're not expecting this to be a cross-origin request, check the origin of the page relative to the origin of the API call, something [protocol, port, domain] seems to be different — if it's an OPTIONS call.)

Related