Using Angular I have a REST api created. For a while I need to route all requests to api which is on other server without changing all request urls in application.
I have configured server to accept Cross-origin resource sharing. All works perfect when i do single request to server. What I want to do is something like "when doing API request change the request url from /api/people/1 to myapiserver/something/api/people/1"
Regards
You can configure a request inceptor on $http for that. See http://docs.angularjs.org/api/ng/service/$http (section Interceptors)
$provide.factory('myHttpInterceptor', function($q) {
return {
'request': function(config) {
config.url = "myapiserver/"+config.url
return config || $q.when(config);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
Related
I have one GET endpoint.
It has HTTP Basic Authentication enabled. I want to create a GET request to the given end point.
https://example.com/api GET
User Name :- admin
Password :- admin
My Code :-
$scope.listData = function() {
$http.get('https://example.com/api').then(function(response) {
$scope.items = response.data;
});
}
What is the recommended way to pass the authentication?
Second argument for the GET is the header part. For ex.
$http.get('www.google.com/someapi', {
headers: {'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}
}).then()..;
the recommended method is http-interceptors.
what interceptor do, you can assume its a hook which call on every api request and response, once you write it, it will automatically add token in every api request. below is the url you read the article.
Angular Authentication: Using the Http Client and Http Interceptors
I want to send an api key for every request I make:
function MyService($http) {
var req = {
method: 'GET',
url: 'https://api.giphy.com/v1/stickers/trending',
headers: {
'api_key':'123'
}
}
return $http(req);
}
but the problem is that all requests are OPTIONS (not GET) and is not sending the api_key. Is that the right way to send headers? thanks
Editing because it was marked as duplicate:
This is not a CORS issue. The error I´m getting is 401. That means authentication failed because the endpoint is not receiving the request header with the api_key.
What you did is totally fine, but if the api_key is always different, so you have to provide the api_key value dynamically in order to be added to the request.
If it is always the same, you have a really better way to do that: through interceptors. And you will set that only one time. Again, this method is if you have to set up some parameter which is always the same, so actually it is for doing standard operations over HTTP requests.
First, you need to define your Interceptor:
myApp.service('MyRequestsInterceptor', [function() {
this.request = function(config) {
config.headers.api_key = 'My Default API KEY';
return config;
};
}]);
And then simply add your interceptor to AngularJS $httpProvided:
myApp.config([ '$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('MyRequestsInterceptor');
} ]);
I'm creating a web app using AngularJS. To test it, I'm running the app in a NodeJS server, using angular-seed template.
In this app, I need to send a JSON message to another host, via POST request, and get the response, so, I'm using CORS.
My request is done by implementing a service that uses AngularJS http service (I need the level of abstraction that $http provides. So, I don't use $resource).
Here, my code. Please pay attention to the fact that I modify $httpProvider to tell AngularJS to send its requests with the appropriate CORS headers.
angular.module('myapp.services', []).
// Enable AngularJS to send its requests with the appropriate CORS headers
// globally for the whole app:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
/**
* Just setting useXDomain to true is not enough. AJAX request are also
* send with the X-Requested-With header, which indicate them as being
* AJAX. Removing the header is necessary, so the server is not
* rejecting the incoming request.
**/
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]).
factory('myService', function($http) {
return {
getResponse: function() {
var exampleCommand = JSON.stringify({"foo": "bar"});
// This really doesn't make a difference
/*
var config = {headers: {
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Headers': 'Content-Type, Content-Length, Accept',
'Content-Type': 'application/json'
}
};
*/
//return $http.post(REMOTE_HOST, exampleCommand, config).
return $http.post(REMOTE_HOST, exampleCommand).
success(function(data, status, headers, config) {
console.log(data);
return data;
}).
error(function (data, status, headers, config) {
return {'error': status};
});
}
}
});
The problem is I can't make it work. I always get this error message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at REMOTE_HOST. This can be fixed by moving the
resource to the same domain or enabling CORS.
But if I do a simple jQuery AJAX call like this:
$.ajax(REMOTE_HOST,
{
dataType: "json",
type: "POST",
data: exampleCommand,
success: function(data) { console.log(data); },
error: function(request, textStatus, errorThrown) { console.log("error " + textStatus + ": " + errorThrown);}
});
It works fine.
So, my questions:
- How do I allow cross-site requests in an AngularJS running under NodeJS?
UPDATE: Thanks to Dayan Moreno Leon's response.
My problem is I need to add cors support to my server. I'm using NodeJS http-server for development and lighttpd for production.
- Why does the simple jQuery POST request work but AngularJS POST request doesn't?
I guess jQuery AJAX requests are cross-domain by default. Not really sure yet.
Many thanks in advance
CORS is not handled on the client but in the server you need to allow CORS on your nodejs app where your angular app is trying to POST. you can try using cors module if you are using express
https://www.npmjs.org/package/cors
other whise you need to check for the options method and return 200 as a response
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Why does the simple jQuery POST request work but AngularJS POST request doesn't?
jQuery uses simple requests while AngularJS uses preflighted requests
In your angular code you can add set Content-Type to application/x-www-form-urlencoded and encode your data using $.param
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?
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.
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.
I am trying to use the $http service on a HTTPS URL with the following code :
var request = $http.post('https://my.custom.url/webservice', privateAttributes.requestData);
request.success(function(data, status) {
}).error(function(data, status) {
console.log('data -', data);
console.log('status -', status);
});
The my.custom.url is on a different domain as my angularJS app, but my webserver is well configured to allow cross domain XHR request. It's supposed to be a public webservice.
When the request is sent, the promise is instantly rejected, so the error() function is triggered. The data is undefined and the status is 0.
On the network tab of my debugger in Chrome, I can see a pending OPTIONS request corresponding to my $http.post() call.
For testing purpose, I tried to do the same request with jQuery $.post() method and it worked with no issue. I think I am making something wrong with the $http service.
Please note that it's not a XSRF issue and if I use the HTTP version of my webservice, the request is a success.
Thanks for your help.
You might need to tell it to send the cookie:
In your config, DI $httpProvider and then set withCredentials to true:
.config(function ($routeProvider, $httpProvider) {
$httpProvider.defaults.withCredentials = true;
//rest of route code
Info on angularjs withCredentials: http://docs.angularjs.org/api/ng.$http
Which links to the mozilla article: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#section_5