Question

I'm creating a simple app using AngularJS that displays the current spot rate (price) of Bitcoin on Coinbase using the Coinbase API.

The app works as expected in Chrome, Safari, Firefox, & Opera, however in Chrome Canary & IE I receive the following error:

Refused to execute script from 'https://coinbase.com/api/v1/prices/spot_rate?callback=angular.callbacks._0' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled.

I'm familiar with AngularJS and I've used $http service to build other apps accessing vendor API's and I've not experienced this issue.

The code below should get the spot rate via the Coinbase API, pass the data to the scope as part of the $http service callback, and refresh the value stored in the scope by making subsequent calls every 60 seconds.

angular.module('CoinbaseApp').controller('MainCtrl', function ($scope, $http, $interval) {

    $scope.getPrice = function(){
        $http.jsonp('https://coinbase.com/api/v1/prices/spot_rate?callback=JSON_CALLBACK').success(function(data){
            $scope.data = data;
        });
    };

    $scope.getPrice();

    $interval($scope.getPrice, 60000);
});

My question: is the strict MIME type checking issue a problem with how Coinbase is serving the json? Or is it an issue with AngularJS $http service and/or how I'm requesting the data?

Était-ce utile?

La solution

When calling out to a service that doesn't respond with appropriate CORS headers and does not directly support JSONP, you can install an http request interceptor to rewrite the request as a GET https://jsonp.afeld.me/, moving the original URL into the config.params (along with a callback). Then define responseTransform to simply extract and return the embedded JSON:

var app = angular.module('jsonp-proxy-request-interceptor', []);
app.service('jsonpProxyRequestInterceptor',
    function JsonpProxyRequestInterceptor($log) {
  var callbackRx = /callback\((.+)\);/gm;
  this.request = function(config) {
    if (config.url === 'https://api.domain.com/' && config.method === 'GET') {
      var apiUrl = config.url;
      config.url = 'https://jsonp.afeld.me/';
      config.params = angular.extend({}, config.params || {}, {
        url: apiUrl,
        callback: 'callback'
      });
      config.transformResponse.unshift(function(data, headers) {
        var matched = callbackRx.exec(data);
        return matched ? matched[1] : data;
      });
    }
    return config;
  };
});
app.config(['$httpProvider', function configHttp($httpProvider) {
  $httpProvider.interceptors.push('jsonpProxyRequestInterceptor');
}]);

You can also fork a gist of this example from https://gist.github.com/mzipay/69b8e12ad300ecaa467a.

Autres conseils

For those inquiring, I was able to resolve my issue via a JSON proxy in node.

https://github.com/afeld/jsonp

The Coinbase REST API only provides JSON endpoints via GET requests, not JSONP (which is typically provided as a CORS alternative). Without JSONP, you can't make a cross domain request to their domain because Allow Access headers aren't being set (most likely for security reasons).

Using the node server-side proxy allowed for me to make the request client-side via the proxy as a normal GET request, since the node proxy provides the returned result of the request with proper headers.

Heroku provides a good tutorial for installing node apps, making the proxy endpoint available publicly.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top