1

I have an annoying problem. I am trying to build a simple website. That website uses an api i build using nodejs and express. While developing the API, i constantly checked functionality with Postman. Everything worked and still works fine (using Postman).

Now I started working on my Website. The first GETs and POSTs worked ok. (I tried some lightweight ajax libs, none worked, only jQuery seems to work for me)

Now I am trying to update a item using the PUT Verb. Again updating works fine using postman. But trying to use jQuery doesn't trigger the right route in express. To check that, I added a simple console.log if express used the last middleware which is also returning a 404 statuscode and one console.log in the function that handles the PUT. Everytime I use jQuery to update an element it goes to 404. If I use Postman I see the message from the PUT function.

My APIController (NodeJS with Express):

let express = require('express');
//let path = require('path');
let bodyParser = require('body-parser');
let mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test', { useMongoClient: true });
require('./Models/InitModels');

let app = express();
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));

let routes = require('./Routes/APIRoutes');
routes(app);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    res.status(404);
    console.log("Returning 404 to request");
});

app.set('port', 2017);
app.listen(2017);
console.log("Starting API Controller");

API Routes (only Karte is important here):

module.exports = function(app) {
let benutzer = require('../Controller/BenutzerController');
let gruppe = require('../Controller/GruppenController');
let zugriffslog = require('../Controller/ZugriffsLogController');
let karten = require('../Controller/KartenController');
let zugriffszeit = require('../Controller/ZugriffsZeitenController');

app.route('/karten')
    .put(karten.put)
    .post(karten.post)
    .delete(karten.delete);

And then the KartenController:

exports.post = (req, res) => {
    if (req.body.search) {
        Karte.find(req.body.search)
            .populate('benutzer').populate('gruppen')
            .exec((err, karten) => {
                res.json(karten)
            });
    } else if(req.body.karte) {
        if (this.createdKarte !== null) {
            res.json({"error": {"code": 110}}); // card needs to be scanned
        } else {
            let newKarte = new Karte(req.body.karte);
            newKarte.save();
            //this.createdKartenDatum = new Date();
            res.json(newKarte);

            // Add Karte To User
            //Benutzer.findOneAndUpdate({_id: newKarte.benutzer}, {$push: {karten: newKarte._id}});
            //Benutzer.findOneAndUpdate({_id: newKarte.benutzer}, {$pull: {karten: newKarten._id}});

            this.kartenCreateDatum = new Date();
            this.createdKarte = newKarte;
            this.kartenScannPending = true;

            // Abort after some time
            setTimeout(scannTimeExpired, timeTillCreationExpires);
        }
    } else if(req.body.status) {
        if (this.kartenScannPending) {
            res.json({"status": {"code": 300}}); // waiting for card to be scanned
        } else if (this.kartenScannFehler !== null) {
            res.json(this.kartenScannFehler); // fehler aufgetreten
            this.kartenScannFehler = null; // aufräumen
        } else if (this.kartenScannErfolgreich) {
            res.json({"status": {"code": 500, "date": this.kartenCreateDatum}}); // karte gescanned
            this.kartenScannErfolgreich = false;
        } else {
            res.json({"status": {"code": 404}}); // no card needs to be scanned
        }
    } else {
        res.json({ "error": "U SUCK" });
    }
};

exports.put = (req, res) => {
    console.log("Trying to put a Card)");
    if (req.body.karte) {
        if (req.body.karte.name && req.body.karte._id) {
            Karte.findOneAndUpdate({_id: req.body.karte._id}, {$set: req.body.karte}, {new: true},(err, karte) => res.json(karte));
        } else {
            res.json({"error": {"code": 120}});
        }
    } else {
        res.json({"error": {"code": 120}});
    }
};

My Javascript looks like this:

$.ajax({
    type: "POST",
    context: this,
    url: "http://localhost:2017/karten",
    data: {
        search: {
            benutzer: {
                _id: this.benutzer._id
            }
        }
    },
    async: true,
    success: function (data) {
        console.log(data);
    },
    dataType: "json"
});

// Zugriffszeiten abfragen
$.ajax({
    type: "PUT",
    context: this,
    url: "http://localhost:2017/karten",
    data: {
        karte: {
            _id: this.karte._id,
            name: "PLS WORK !!!"
        }
    },
    async: true,
    success: function (data) {
        console.log(data);
    },
    dataType: "json"
});

The result:

First one:

is working and giving me an array of two cards

Second one:

getting me an ERR::EMPTY_RESPONSE (because of the 404) and the nodejs console outputs "Returning 404 to request"

Trying the same with Postman, everything works and the cards get updated

I realy hope somone can help me with that, as I am working on this quite a long time now and cant seem to see my mistake.

Thanks for reading everything :)

4
  • Did you check the permissions settings? Ajax request can not simply pass through different ports. Commented Oct 20, 2017 at 23:02
  • 1
    I'm wondering if this is a cross origin request from the browser. If so, you will have to support the OPTIONS request on your server so that the cross origin request will be allowed for a PUT request. A simple POST or GET will work with only the CORS header stuff you are already doing, but a PUT likely requires a handler for an OPTIONS request. Commented Oct 20, 2017 at 23:27
  • 1
    If you open the network tab in your browser debugger and watch what the browser does when you make these ajax calls, you can probably see the OPTIONS request being sent and returned with a 404. Commented Oct 20, 2017 at 23:30
  • @jfriend00 Thanks, that was the hint for the right solution. The problem was, that my API didnt send a OK-Code to for the OPTIONS. I fixed that now everything works fine. You are a life saver :) Commented Oct 21, 2017 at 12:54

1 Answer 1

1

Thanks to jfriend00, I found the solution to the problem. I didnt respont to the options-request properly. I had to add some lines of code to my APIController:

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

    // The routes wont fire on that options-request, so it sends a 404 response and thus the ajax request times out
    //intercepts OPTIONS method
    if ('OPTIONS' === req.method) {
        //respond with 200
        console.log("Received options request");
        res.send(200);
    }
    else {
        //move on
        next();
    }
});

Now everything works as expected.

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.