0

With NodeJs I have set up an API which works (I can see the JSON result in my Browser). In Angular I have a socket.io chat which runs via http on port 3030. I am also running an apache server (with xampp) which serves the AngularJs frontend.

As soon as I want to make a request from Angularjs to the Nodejs API I get the following error in the browsers console

XMLHttpRequest cannot load localhost:3030/api/feed. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

From what I understood after googling is that Angular can't communicate with the API as long as I dont have an HTTP server running in NodeJS. But can I run the socket.io server and the HTTP server for the api in the same process?

server.js

var express = require('express');
var app = express();
var http    = require('http').Server(app);
var io = require('socket.io')(http);

var routes  =   require('./app/api/routes');
app.use('/api', routes);

var chatMembers = {};


io.on('connection', function(socket){

 socket.on("new-message", function(msg){
  console.log(msg);
  var username = msg[username];
  var message = msg[message];
  io.emit("receive-message", msg);
 })

 socket.on("new-connection", function(username){
  chatMembers[socket.id] = username;
  console.log(chatMembers);

  io.emit("online-list", createOnlineList());
 })

 socket.on("disconnect", function(){
  if(chatMembers[socket.id] != undefined){
   console.log(" " + chatMembers[socket.id] + " hat die Verbindung getrennt.");
   delete chatMembers[socket.id];
   io.emit("online-list", createOnlineList());
  }
 })
});


function createOnlineList(){
 //returns list of every member connected to the socket (only name)
   var onlinelist = [];
 for(var index in chatMembers){
  onlinelist.push(chatMembers[index]);
 }
 return onlinelist;
}


http.listen('3030', function(){
  console.log("Server online");
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
controller.js

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
angular.module('coursemate')
    .controller("chatCtrl", ['$rootScope','$scope', '$http', function($rootScope, $scope, $http){
  var vm = this;
  var socket = window.io('localhost:3030/');
  vm.newMessage = undefined;
  vm.username = undefined;
  vm.messages = [];
  vm.onlinelist = [];
  vm.sendBtnDisabled = true;
  vm.connected = false;


  //socket acions
  socket.on("receive-message", function(msg){
   //socket server send message to us
   $scope.$apply(function(){
     vm.messages.push(msg);
   });
  });

  socket.on("online-list", function(list){
   //server sends us refreshed list of members
   $scope.$apply(function(){
     vm.onlinelist = list;
   });
  });

  socket.on('disconnect', function(){
   //connection failed
   vm.connected = false;
   vm.keyEventSendMessage(null);
  });

  socket.on('connect', function(){
   //connection established
   vm.connected = true;
   vm.keyEventSendMessage(null);
  });
  vm.username = undefined;



  vm.sendMessage = function(){
   //we send messsage to socket server
   var newMessage = {
    username: vm.username,
    message: vm.newMessage
   };
   socket.emit("new-message", newMessage);

   var config = {
                headers : {
                    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
                }
            }
            var data = $.param({
                user: vm.username,
                content: vm.newMessage
            });
   $http.post('app/database/database.php?req=1', data, config).success(function(data) {
         });

         vm.newMessage = undefined;
         vm.keyEventSendMessage(null);
  };

  vm.createUser = function(username){
   // we "log in" as users
   vm.username = username;
   socket.emit("new-connection", username);
  }
   vm.keyEventSendMessage = function(event){
    //fired on keyhit at message input
    if(typeof(vm.newMessage) != 'undefined' && vm.newMessage != null && vm.newMessage != '' && vm.connected){
     vm.sendBtnDisabled = false;
     if(event != null && event.keyCode == 13){
      vm.sendMessage();
     }
    }else{
     vm.sendBtnDisabled = true;
    }
   }

  $http.get('localhost:3030/api/feed').success(function(data) {
   console.log(data);
  });

    }]);
Marius
  • 19
  • 1
  • 9
  • Possible duplicate of [XMLHttpRequest cannot load https://www.\[website\].com/](http://stackoverflow.com/questions/35553500/xmlhttprequest-cannot-load-https-www-website-com) – baao May 16 '17 at 20:32
  • This is a browser CORS policy issue. Because you load the angular app from one port, and make Ajax calls to another port, the browser blocks it. You could do one of the following: 1. setup the NodeJS server to serve your angular app at the base url, or if not possible, 2. configure a proxy setting on your XAMPP server to redirect calls to a path (i.e. /api/*) to the NodeJS app on `localhost:3030` – julian soro May 16 '17 at 21:26
  • A 3rd option, just to get it working, but really not recommended for your production API, is accept all origins: [How to enable cross-origin resource sharing (CORS) in the express.js framework on node.js](http://stackoverflow.com/a/11182153/1799146) – julian soro May 16 '17 at 21:30
  • @JulianSoro I tried setting up a NodeJs server to run my Angularjs on which was easier than expected. I think the server is running now aswell. However now I get an AngularJs error `Uncaught Error: [$injector:modulerr]` and nothing is loaded. This is my [app.js](https://pastebin.com/5mbuPN0S) and the [controller for the view](https://pastebin.com/00NN1P8G) – Marius May 17 '17 at 07:44
  • If anyone looking for Nodejs API boilerplate with Expressjs and MongoDB. Try this: https://github.com/maitraysuthar/rest-api-nodejs-mongodb – Maitray Suthar Aug 17 '19 at 09:57

1 Answers1

1

This is due to CORS policy, as Julian Soro pointed above.

I was dealing with this problem before when testing on my virtual machine and access the API on the host. If you are using Chrome, probably it could be helpful to mention there is an extension to overcome that. You could download this extension to allow CORS on Chrome. Here is the link to 'Allow-Control-Allow-Origin:*'.

Hope this could help.

Darren Christopher
  • 3,893
  • 4
  • 20
  • 37