Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access-Control-Allow-Origin and Angular.js $http

Whenever I make a webapp and I get a CORS problem, I start making coffee. After screwing with it for a while I manage to get it working but this time it's not and I need help.

Here is the client side code:

$http({method: 'GET', url: 'http://localhost:3000/api/symbol/junk', 
            headers:{
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
                'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
                'X-Random-Shit':'123123123'
            }})
        .success(function(d){ console.log( "yay" ); })
        .error(function(d){ console.log( "nope" ); });

The server side is a regular node.js with an express app. I have an extention called cors and it's being used with express this way:

var app = express();
app.configure(function(){
  app.use(express.bodyParser());
  app.use(app.router);
  app.use(cors({origin:"*"}));
});
app.listen(3000);

app.get('/', function(req, res){
    res.end("ok");
});

If I do

curl -v -H "Origin: https://github.com" http://localhost:3000/

It gets back with:

* Adding handle: conn: 0x7ff991800000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ff991800000) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 3000 (#0)
*   Trying ::1...
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:3000
> Accept: */*
> Origin: https://github.com
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Tue, 24 Dec 2013 03:23:40 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
ok

If I run the client side code, it brigs up this error:

OPTIONS http://localhost:3000/api/symbol/junk No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. angular.js:7889
XMLHttpRequest cannot load http://localhost:3000/api/symbol/junk. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. localhost/:1
nope 

Checking Chromes headers:

Request URL:http://localhost:3000/api/symbol/junk
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,es;q=0.6,pt;q=0.4
Access-Control-Request-Headers:access-control-allow-origin, accept, access-control-allow-methods, access-control-allow-headers, x-random-shit
Access-Control-Request-Method:GET
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:3000
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Response Headersview source
Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
Date:Tue, 24 Dec 2013 03:27:45 GMT
X-Powered-By:Express

Checking the request headers I see that my test string X-Random-Shit is present in the "Access-Control-Request-Headers" but it's value is not there. Also, in my head I was expecting to see one line for each one of the headers I am setting, not a blob.

UPDATES ---

I changed my frontend to jQuery instead of Angular and made my backend like this:

var app = express();
app.configure(function(){
  app.use(express.bodyParser());
  app.use(app.router);
});
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,DELETE');
    res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
    if ('OPTIONS' == req.method){
        return res.send(200);
    }
    next();
});

app.get('/', function(req, res){
    res.end("ok");
});

Now it works with GET but does not with anything else (PUT, POST..).

I'll see if any of you comes up with a solution. In the mean time in throwing the RESTful concept out the window and making everything with GETs.

like image 554
PCoelho Avatar asked Dec 24 '13 03:12

PCoelho


People also ask

What is $HTTP in AngularJS?

$http is an AngularJS service for reading data from remote servers.

How do you resolve CORS issue in angular 8?

CORS error due to browser's same origin policy. To get around this, you need to tell your browser to enable your client and your server to share resources while being of different origins. In other words, you need to enable cross-origin resource sharing or CORS in your application.

How do you modify the $HTTP request default Behaviour?

To add or overwrite these defaults, simply add or remove a property from these configuration objects. To add headers for an HTTP method other than POST or PUT, simply add a new object with the lowercased HTTP method name as the key, e.g. $httpProvider. defaults.


4 Answers

I'm new to AngularJS and I came across this CORS problem, almost lost my mind! Luckily i found a way to fix this. So here it goes....

My problem was, when I use AngularJS $resource in sending API requests I'm getting this error message XMLHttpRequest cannot load http://website.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. Yup, I already added callback="JSON_CALLBACK" and it didn't work.

What I did to fix it the problem, instead of using GET method or resorting to $http.get, I've used JSONP. Just replace GET method with JSONP and change the api response format to JSONP as well.

    myApp.factory('myFactory', ['$resource', function($resource) {             return $resource( 'http://website.com/api/:apiMethod',                         { callback: "JSON_CALLBACK", format:'jsonp' },                          {                              method1: {                                  method: 'JSONP',                                  params: {                                              apiMethod: 'hello world'                                         }                              },                             method2: {                                  method: 'JSONP',                                  params: {                                              apiMethod: 'hey ho!'                                         }                              }             } );      }]); 

I hope someone find this helpful. :)

like image 136
Wreeecks Avatar answered Sep 17 '22 15:09

Wreeecks


I've had success with express and editing the res.header. Mine matches yours pretty closely but I have a different Allow-Headers as noted below:

res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 

I'm also using Angular and Node/Express, but I don't have the headers called out in the Angular code only the node/express

like image 33
wnordmann Avatar answered Sep 19 '22 15:09

wnordmann


Writing this middleware might help !

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();
});

for details visit http://enable-cors.org/server_expressjs.html

like image 35
Vickar Avatar answered Sep 21 '22 15:09

Vickar


Adding below to server.js resolved mine

    server.post('/your-rest-endpt/*', function(req,res){
    console.log('');
    console.log('req.url: '+req.url);
    console.log('req.headers: ');   
    console.dir(req.headers);
    console.log('req.body: ');
    console.dir(req.body);  

    var options = {
        host: 'restAPI-IP' + ':' + '8080'

        , protocol: 'http'
        , pathname: 'your-rest-endpt/'
    };
    console.log('options: ');
    console.dir(options);   

    var reqUrl = url.format(options);
    console.log("Forward URL: "+reqUrl);

    var parsedUrl = url.parse(req.url, true);
    console.log('parsedUrl: ');
    console.dir(parsedUrl);

    var queryParams = parsedUrl.query;

    var path = parsedUrl.path;
    var substr = path.substring(path.lastIndexOf("rest/"));
    console.log('substr: ');
    console.dir(substr);

    reqUrl += substr;
    console.log("Final Forward URL: "+reqUrl);

    var newHeaders = {
    };

    //Deep-copy it, clone it, but not point to me in shallow way...
    for (var headerKey in req.headers) {
        newHeaders[headerKey] = req.headers[headerKey];
    };

    var newBody = (req.body == null || req.body == undefined ? {} : req.body);

    if (newHeaders['Content-type'] == null
            || newHeaders['Content-type'] == undefined) {
        newHeaders['Content-type'] = 'application/json';
        newBody = JSON.stringify(newBody);
    }

    var requestOptions = {
        headers: {
            'Content-type': 'application/json'
        }
        ,body: newBody
        ,method: 'POST'
    };

    console.log("server.js : routes to URL : "+ reqUrl);

    request(reqUrl, requestOptions, function(error, response, body){
        if(error) {
            console.log('The error from Tomcat is --> ' + error.toString());
            console.dir(error);
            //return false;
        }

        if (response.statusCode != null 
                && response.statusCode != undefined
                && response.headers != null
                && response.headers != undefined) {
            res.writeHead(response.statusCode, response.headers);
        } else {
            //404 Not Found
            res.writeHead(404);         
        }
        if (body != null
                && body != undefined) {

            res.write(body);            
        }
        res.end();
    });
});
like image 34
Babu M Avatar answered Sep 19 '22 15:09

Babu M