AngularJS: Setting correct 'Referer' header for $http - angularjs

It looks like when you send off a request using the $http service, the referer header is set to the base url without the angular $location information.
How do you go about appending the $location.path() to that header for all requests?
Our API calls will log that referer header when an error occurs; however, it would be very helpful if we could store the user's actual location ("stackoverflow.com/#/question/1234" opposed to just "stackoverflow.com/")

I ended up just doing something like this:
$httpProvider.interceptors.push(function ($location) {
return {
request: function (config) {
config.headers["RefererFullUrl"] = $location.absUrl();
return config;
}
};
});
It doesn't look like the browsers are too happy if you try to change the 'referer' url, so I'm just naming it something else, and looking for that header specifically on the server

Related

Prevent $http service execution using Interceptor

I am building an authentication solution with Angular. I am using Interceptors to validate Request and if there is not valid token prevent from further processing and redirect. Here is my simplified Interceptor:
prism.service('APIInterceptor', function($rootScope) {
var service = this;
service.request = function(config) {
.....
return config;
};
})
Just for the sake of POC that I am working on what would the correct way of stopping this request from any further processing be?
Thanks
From the Angular Docs on Interceptors for the request method:
request: interceptors get called with a http config object. The function is free to modify the config object or create a new one. The function needs to return the config object directly, or a promise containing the config or a new config object.
The rest of the documentation can be found here. From this you can see that the method can also return a promise (which is actually pretty awesome) so you could always reject it.
Try something like this:
prism.service('APIInterceptor', function($q, $rootScope) {
this.request = function(config) {
if( /*config is not valid*/ ) {
return $q.reject({message: 'ERROR, ERROR... INTRUDER ALERT!', status: 401, config: config});
} else {
return config;
}
};
});
And see how it might be handled (I have no idea what your application will do). Let me know if it works out for you!
EDIT: My answer has been accepted, but is incomplete and it will haunt me forever if I don't complete it. So, after writing some test code of my own I've realized that you can do 1 of 2 things in this situation. The first is to handle the unauthorized request in the interceptor:
...
this.request = function(config) {
if(/* config is not authorized */) {
// Do something here like redirect/issue another request... whatever
return $q.reject({/*whatever the hell you want*/});
} else ...
};
...
This obviously works best if you want to handle all unauthorized requests the same. If you don't, however, the second option is to defer to the service that issued the request. For example, if you're using $http you can do this:
$http.get('/words/words/words/').then(function(){
// This is where you handle a successful request.
}, function(error) {
// Handle your error here. Please take note that this error message is
// whatever you sent back in the `reject` previously
});
Hopefully that clears a few things up.

AngularJS $resource GET params appear in URL

My REST backend [ based on NodeJS/express/mongojs] is complaining 404 (not found) when Params are attached as part of URL. Backend rest interface is coded as below;
var express = require('express');
var router = express.Router();
router.get('/login', auth.signin); //auth.signin is code to verify user
Above REST service is consumed by AngularJS based frontend through $resource as below;
Definition:
angular.module('myapp').factory('signinmgr', function($resource) {
return $resource("http://localhost:3000/login", {}, {
'get': {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}});
Usage:
signinmgr.get({'username':'myname', 'password':'mypass'}, function(data){
//success
}, function(x){
//failed
});
Problem:
Frontend code above produces a URL to consume REST service where parameters are part of URL i.e. http://localhost:port/login?username=myname&password=mypass [if I use GET method, POST is OK]. I wanted my front end to keep URL as http://localhost:port/login and post any parameters through body as backend is using req.body.paramName to read those. [Actual Solution]
If (1) cannot be done, and my frontend is sending params as part of URL, I needed help as to know how to equip my backend to allow this URL with parameters so that backend doesnt return 404 as the base URL http://localhost:port/login is already there.
PS: for (1), I tried this thread with data:{username:'',password:''} but of no use. Please help if I am missing something very obvious or some concept.
Try the $http service instead:
angular.module('myapp').factor('signinmgr', function($http) {
return {
login: function (username, password) {
$http.post("http://localhost:3000/login", {
username: username,
password: password
}
}
};
});
signinmgr.login('myname', 'mypass').then(function(data){
//success
}, function(x){
//failed
});
Each request that my nodejs/expressjs backend receives has three places for passed attributes;
params{}
query{}
body{}
My problem (1) cannot be fixed in case I want to use GET method since with GET request parameters are visible as part of URL i.e. http://localhost:port/login?username=myname&password=mypass. To send my username/password I had to use POST that sends parameters as part of body{}.
My problem (2) was that I was using GET and mistakenly looking for parameters in body{} of request. Instead, parameters passed as part of URL in GET request are added to query{} of the request.

API-key header is not sent (or recognized). Angularjs

I'm trying to access an API with AngularJS but I get the following error:
XMLHttpRequest cannot load http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://purepremier.com' is therefore not allowed access.
This is my code for the service:
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.get('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});
I use an authentication token (api key) to access the api, but according the API owner this API key header is not sent or recognized. Do you have any idea how I can adapt the code to make this work? thanks!
You should hide that API key before posting on a public site such as this. I would advise you regenerate your key (if possible) just in case - better safe than sorry.
Assuming your site url is 'http://purepremier.com' from the error message, the API should add a 'Access-Control-Allow-Origin' header with your site URL to allow you access. Have a look here for more information.
This is not directly related to your problem, but I notice you are setting $http defaults every time getTeams() is called. You should either set this outside of the actual function call (preferably in a run block), or just send the GET request with that header specifically applied. As the API key is specific (I assume) to that call, you may not want to be sending it to anyone and everyone, every time you make a HTTP request.
Change your factory code like this:
factory('footballdataAPIservice', function($http) {
return {
getTeams: function(){
return $http({
url:'http://www.football-data.org/alpha/soccerseasons/398/leagueTable',
headers: { 'X-Auth-Token': 'your_token' },
method: 'GET'
}).success(function(data){
return data;
});
}
}
});
Inject factory in your controller and retreive the data:
.controller('someController',function(footballdataAPIservice,$scope){
footballdataAPIservice.getTeams().then(function(data){
$scope.teams=data;
console.log($scope.teams)
});
});
Here is the working plunker
You change the Auth-Token To Authorization
$http.defaults.headers.common['Authorization'] = 'token';
Because token is send via headers using Authorization
try jsonp
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.jsonp('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});

AngularJS remote client Properties share to controllers/services

I want to develop an AngularJS web client for which the REST backend may be located on a different server.
So basically I am thinking of having a property input field on the frontend where for each session I will enter the base REST url (e.g., http://localhost:8080/backend/rest/)
Is there some sort of best practice to be able to share the base url amongst all controller/factories/services in order to include it for all $http requests?
I would configure an HTTP request interceptor service that would simply prepend the value to the URL passed to the $http service. Something like the following (not tested):
// register the interceptor as a service
$provide.factory('pathPrependerInterceptor', function() {
var _path = 'http://localhost:8080/backend/rest'; // default value
return {
request: function(config) {
config.url = _path + config.url
return config;
},
setPath: function(path) {
_path = path;
}
}
});
$httpProvider.interceptors.push('pathPrependerInterceptor');
I think the bast way would be to acomplish this with the use of interceptors. You can read more about this topic in the AngularJs documentation.
The idea is to set up an interceptor that will preappend the base url to each request something like this:
var app = angular.module('MyApp',[]);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q) {
return {
'request': function(config) {
config.url = "http://api.openweathermap.org/data/2.5/" + config.url
return config;
}
};
});
}]);
I hope you got an idea.
There is JSFiddle that incorporates this idea.
The other answers are from a more experienced bunch, so take this with a pinch of salt, but they seem like overkill to me. You're configuring an application-wide variable which needs injection. Using
module.value("baseRestUrl", ...)
lets you inject baseRestUrl wherever it's required.

AngularJS $resource not sending custom headers

I'm using angular and angular-resource version 1.1.5 and I'm using a $resource to make a request to a REST service. But it seems like the custom headers is not appended to the request. My definition is as below. Is there anything I did wrong?
myApp.factory('User', function($resource) {
var User = $resource('http://localhost\\:7017/mydomain/users/jack', { }, {
get: {
method: 'GET',
isArray: false,
headers: {'X-Requested-By':'abc'}
}
});
return User;
});
Read this to see how to configure default headers in one place: http://docs.angularjs.org/api/ng.$http
EDIT:
Your header must be included in Access-Control-Allow-Headers header in response to the OPTIONS request, which is sent automatically prior to your GET request.
You can modify the default headers inside the $httpProvider.
the headers are an object and separated intocommon, patch, post and put
so if you want to change the default for all your requests, just do a
$httpProvider.defaults.headers.put['Content-Type'] = 'application/json';
You have to call get method by using its name, i.e User.get(callback)
It seems that custom headers do not get sent when get method is called with User.query(callback)

Resources