I am trying to call the CTA API (http://www.transitchicago.com/developers/bustracker.aspx) from my local Wamp server. However, when doing the fetch via backbone collection I get:
XMLHttpRequest cannot load http://www.ctabustracker.com/bustime/api/v1/getroutes?key=xx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
collection:
define([
'models/route',
'core'
], function (Route) {
return Backbone.Collection.extend({
initialize: function () {},
model: Route,
//url: function () {
// return 'http://www.ctabustracker.com/bustime/api/v1/getroutes?key=xx';
//},
url: function () {
return '/apiproxy.php?method=getroutes';
},
});
});
I know this is a common issue but haven't found a concise answer yet.
How can I resolve this issue? Update Added the apiproxy but am getting this response:
Remote Address:127.0.0.1:80
Request URL:http://localhost/apiproxy.php?method=getroutes
Request Method:GET
Status Code:200 OK
Request Headersview parsed
GET /apiproxy.php?method=getroutes HTTP/1.1
console:
responseText: "$url = "http://www.ctabustracker.com/bustime/api/v1/{$_GET['method']}? key=xx";
↵echo file_get_contents($url);
SyntaxError {stack: (...), message: "Unexpected token $"}
message: "Unexpected token $"
stack: (...)
You can solve this problem, but it's not a simple case of "add this line to your JavaScript and everything will be fine."
You're running up against the same-origin security policy built into every web browser. 'Origin' basically means 'the same site'; my JavaScript on example.com can access whatever it likes on example.com, but it's not allowed to read anything from demonstration.com, example.net, or api.example.com. That's got a different origin. Here's a table of what counts as the same origin.
Without it, I could write a web page that steals all your gmail and private Facebook photos. My malicious JavaScript would make web requests to gmail.com and facebook.com, find the links to your emails & photos, load that data too, and then send it off to my own server.
Obviously, some web pages are designed to be used by other people. APIs, for instance, generally want to allow access to their data so people can build web apps. The people building those APIs can serve their content with
Access-Control-
headers that tell browsers it's OK to allow requests from other sites. This is called CORS - Cross-Origin Resource Sharing. The reason you get that error message is because the ctabustracker.com developers haven't added any CORS headers. Thus, you can't access their API from your JavaScript.So what's the solution? you have two options:
The same-origin policy is only standing in your way in your JavaScript. You can do whatever you like on the server; at its simplest, you could create an
apiproxy.php
along these lines:And then access it from your JavaScript as
/apiproxy.php?method=getroutes
, and pass extra parameters in via a standard query string (for instance,/apiproxy.php?method=test&foo=bar&cat=dog
results in a request tohttp://www.ctabustracker.com/bustime/api/v1/test?key=xx&foo=bar&cat=dog
). Now your JavaScript is making a request to your own server, so you won't have any problems with the same-origin policy.You can, of course, make your proxy as smart as you like. It could cache responses, convert your XML to JSON, pre-fetch the results for likely next requests, or 100 other things that may be useful for your app.