1

I am trying to hit 3rd party api using angularjs as shown below

Only in chrome I was able to see this issue and IE works perfectly I got the error as...

XMLHttpRequest cannot load https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
:3000/#/home:1 XMLHttpRequest cannot load https://www.w3schools.com/angular/customers.php. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
homeController.js:23 failure
:3000/#/home:1 XMLHttpRequest cannot load http://www.w3schools.com/angular/customers.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

Angular JS code is:

angular.module('homeModule', []).
controller('HomeCtrl', ['$scope','$http'
    , function($scope,$http ){
        $http.get("http://www.w3schools.com/angular/customers.php").then(function (response) {
            $scope.test1 = response.data.records;
        });

        $http.get("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526").then(function (response) {
              $scope.test2 = response;
          });

        $http({
            method: 'GET',
            url: "https://www.w3schools.com/angular/customers.php",
            headers: {
                'Access-Control-Allow-Origin': '*'
            }
        }).
        success(function(status) {
            $scope.test3 = response;
        }).
        error(function(status) {
            console.log("failure");
        });


    }])

and My server.js is

var express = require('express'),
http = require('http');
var 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(express.static(__dirname + '/public'))
.use('/node_modules',  express.static(__dirname + '/node_modules'));

http.createServer(app).listen(3000, function () {
  console.log("Server ready at http://localhost:3000");
});
Kartheek Sarabu
  • 3,886
  • 8
  • 33
  • 66
  • http://stackoverflow.com/questions/10636611/how-does-access-control-allow-origin-header-work?rq=1 – avck Mar 28 '16 at 09:56
  • @avck for me it is not working.. I added those headers in server side. You can refer the above code – Kartheek Sarabu Mar 28 '16 at 10:00
  • It should be added at the server you are requesting data from. In your case it would be w3school. Unless it is open for public access they won't respond to your requests – avck Mar 28 '16 at 10:04
  • But if I type the same URL in browser the data is showing up. So you are saying that in anyway I can't see the data... But in IE I am not getting any error. It works perfectly – Kartheek Sarabu Mar 28 '16 at 10:07
  • use `$http.jsonp()` instead of `$http.get()`. This is a cross domain request so you're gonna need to use jsonp. – AdityaParab Mar 28 '16 at 10:18
  • Depends on the browsers security implementation. Cors is a security feature. Maybe check version of IE – avck Mar 28 '16 at 10:18
  • When you type it as a URL it's not cross origin. – avck Mar 28 '16 at 10:19
  • @AdityaParab I am getting the error as `Refused to execute script from 'https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78‌​.536526' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.` – Kartheek Sarabu Mar 28 '16 at 10:29
  • @avck Means there is no way to get the data from 3rd party API? – Kartheek Sarabu Mar 28 '16 at 10:30
  • There is a way. The server should allow your hostname or allow all hosts. Other than that 3rd party servers also ask for development keys. So they can verify your identity. – avck Mar 28 '16 at 10:36
  • if 3rd party is not allowed to do that, you cant do that in client, you express server have to fetch that for client – YOU Mar 28 '16 at 10:38
  • You can use your server as pass through. Meaning you send request to your express server which in turn contacts 3rd party. And sanitize the response maybe and return to angular app – avck Mar 28 '16 at 10:45

1 Answers1

0

First thing, you're requesting data from 3rd party servers. NOT your server. So setting headers and access control information on your server is not going to change anything.

The only workaround you can use here is to use padded JSON.

In angular, you'll need to use $http.jsonp and not $http.get.

Change your code to

$http.jsonp("http://www.w3schools.com/angular/customers.php").then(function (response) {
    $scope.test1 = response.data.records;
});

$http.jsonp("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526").then(function (response) {
    $scope.test2 = response;
});

EDIT:

Forgot to mention callback setting in case of JSONP requests. You'll need to specify a callback parameter as ?callback=JSON_CALLBACK in your URLs.

Change your code to

$http.jsonp("http://www.w3schools.com/angular/customers.php?callback=JSON_CALLBACK").then(function (response) {
    $scope.test1 = response.data.records;
});

$http.jsonp("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526?callback=JSON_CALLBACK").then(function (response) {
    $scope.test2 = response;
});

And it should work.

EDIT 2:

As per the suggestion from avck, the above method is not only bad but also it involves security risks.

The right way to do this is as follows.

You're gonna have to change YOUR server.

First do,

npm install request

Then in your server.js

var express = require('express'),
http = require('http'),
request = require('request');
var app = express();

/* This is not needed
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.get('/getDataFromW3Schools', function(req, res, next){
    var url = 'http://www.w3schools.com/angular/customers.php';
    request(url, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body);
            res.json(body);
        }
    });

});

app.get('/getDataFromForecast', function(req, res, next){
    var url = 'https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526';
    request(url, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body);
            res.json(body);
        }
    });

});

app.use(express.static(__dirname + '/public')).use('/node_modules',  express.static(__dirname + '/node_modules'));

http.createServer(app).listen(3000, function () {
    console.log("Server ready at http://localhost:3000");
});

And in your client side, you'll have to do,

$http.get("/getDataFromW3Schools").then(function (response) {
    $scope.test1 = response.data.records;
});

$http.get("/getDataFromForecast").then(function (response) {
    $scope.test2 = response;
});

PLEASE NOTE: Now we're using $http.get.

AdityaParab
  • 7,024
  • 3
  • 27
  • 40
  • It says `Refused to execute script from 'https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.` – Kartheek Sarabu Mar 28 '16 at 10:25
  • Please note that this method can be a security threat. – avck Mar 28 '16 at 10:38
  • I am able to get the response thanks for the solution but can't we do it through `http.get` – Kartheek Sarabu Mar 28 '16 at 10:39
  • Yes. This is not going to work in case of normal `GET` (or any of the standard http methods for that matter). – AdityaParab Mar 28 '16 at 10:40
  • like @avck has correctly, pointed out, this involves security threat. It'd suggest refactoring this and making simple http request from YOUR server to the third party server. And then using get request TO your server. – AdityaParab Mar 28 '16 at 10:41
  • I used request module and it its loading at all but I need similar to above solution – Kartheek Sarabu Mar 28 '16 at 11:04
  • It's not possible to do that without using JSONP. If you still want to use GET then 1) Contact 3rd party vendors and ask them to disable their security (which they won't) OR 2) Start Google chrome with `--disable-web-security` flag. Both of these alternatives are bad. – AdityaParab Mar 28 '16 at 11:08
  • I am getting the error as `GET http://localhost:3000/getDataFromW3Schools net::ERR_EMPTY_RESPONSE` – Kartheek Sarabu Mar 28 '16 at 11:19
  • I found the only solution is to call with jsonp – Kartheek Sarabu Mar 30 '16 at 15:27