trouble changing request headers in Firefox with AngularJS - angularjs

My backend requires the 'Content-Type' request header to be exactly 'application/json'. This is a CORS request and everything works fine in Chrome. The exact header, from developer tools network tab source:
Content-Type: application/json
I set this in AngularJS with $http.default.headers.post and it works fine in Chrome. However it doesn't work in Firefox. Firefox sends this instead:
Content-Type: application/json; charset=UTF-8
I tried to change headers by:
settings $http.default.headers (for .post, .common)
setting custom headers for one request
using an $http interceptor
All of those methods work well in Chrome, but not in Firefox. The request contains data.
If I remove the 'Content-Type' header all together, it still is sent, but then it is:
Content-Type: text/plain; charset=UTF-8
(this happens in both Chrome and Firefox).
This leads me to think that the browser forces the header :)
How can I circumvent this in Firefox?

Firefox has charset=UTF-8 hard-coded for string payloads.
You may however send a Blob instead:
var r = new XMLHttpRequest();
r.open("POST", ...);
r.send(new Blob(
[JSON.stringify({a:1})],
{type:"application/json"}
));
This also works perfectly fine with the angular $http XHR wrapper:
$http({
method: "POST",
url: "/echo/json",
headers: {
"Content-Type": "application/json"
},
data: new Blob([JSON.stringify({
a: 1
})])
});
Fiddle

Related

Browser fetch works, but AngularJS $http service has CORS error

I would like to understand why the AngularJS $http service doesn't work and the fetch API works.
Below is the AngularJS code:
const $http = angular.element(document.body).injector().get('$http')
$http({
method: 'GET',
url: 'http://192.168.1.126:8080/saiku/rest/saiku/admin/datasources/',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4='
}
})
This gives me this error:
angular.js:12845 OPTIONS http://192.168.1.126:8080/saiku/rest/saiku/admin/datasources/ 403 ()
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 403.
The weird part is that this:
fetch('http://192.168.1.126:8080/saiku/rest/saiku/admin/datasources/', {
method: 'GET',
headers: {
'Authorization': 'Basic YWRtaW46YWRtaW4='
}
}).then((r) => r.json()).then(console.log)
Gives me the correct response
I know this could be a CORS error, but i've added the CORS filter on my tomcat so everything should work (and fetch works).
Is this a bug in fetch or $http?
While i was writing this question i found the answer:
On my AngularJS app, there was a config file that was setting this:
$httpProvider.defaults.headers.get['If-Modified-Since'] = '0';
And this (along with other headers), makes the request a preflighted one, as peer the CORS documentation:
[...] Apart from the headers set automatically by the user agent (for
example, Connection, User-Agent, or any of the other header with a
name defined in the Fetch spec as a “forbidden header name”), the
request includes any headers other than those which the Fetch spec
defines as being a “CORS-safelisted request-header”, which are the
following:
Accept Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
Last-Event-ID
DPR
Save-Data
Viewport-Width
Width
So the fetch API worked because it wasn't setting that (If-Modified-Since) header, and the $http service was.

How to make this Angular http get request (with basic authentication) work?

I am trying to debug my angular app with chrome dev console.I want to send a get request to a local server from angular. I've tried the following:
$http = angular.element($0).injector().get('$http');
$base64 = angular.element($0).injector().get('$base64');
var auth = $base64.encode("user:passwd");
var authHeaders = {"Authorization": "Basic " + auth,"Access-Control-Allow-Origin":"*"};
$http.get("url",{headers:authHeaders,method:"GET"})
After reading this answer:
https://stackoverflow.com/a/30296149/1496826
I thought that custom header is the problem. So, I tried putting the authorization headers in the body:
$http.get("url",{data: {"Authorization": "Basic " + auth,"Access-Control-Allow-Origin":"*"},method:"GET"})
But I am still getting the same error:
XMLHttpRequest cannot load "url". No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin 'null' is
therefore not allowed access. The response had HTTP status code 401.
This same get request works fine from Postman:
var settings = {
"async": true,
"crossDomain": true,
"url": "url",
"method": "GET",
"headers": {
"authorization": "Basic bWdhcasdasd",
"cache-control": "no-cache",
"postman-token": "XXXXXX-XXXXXX-xXXXX-xXXXX"
}
}
I have tried several other variation like - $http default / common header etc. but everything failed. Please help.
this is a CORS issue.
CORS headers must be handled server side, i don't see your server side code here but in order to let this error disappear you must specify which domain are allowed to request resources.
the exception is caused by the browser that intercept the server response check the headers and if it doesn't find the Allow-Control-Allow-Origin header it won't forward the response to your code (this happens only for cross origin request).
This is why Postman let you see the response, because it doesn't do what chrome does, doesn't make any check.
As i said the correct solution is to fix your server side code and specify the Allow-Control-Allow-Origin header , alternatively a quick but temporary workaround is to install this plugin for chrome that will intercept the server response and add the Allow-Control-Allow-Origin to * (means any domain) this trick will fool chrome and make you see the response.

Angularjs "HTTP/1.1 401 Unauthorized" error in chrome

I have an angularjs application which is consuming a WebAPI created using WCF.
Angularjs application is making call to a WebAPI to fetch client details.
When i run both the projects (angularjs and WCF project) on my local machine. Everything works fine.
After deploying the project on development server I am facing issue while testing my angularjs application in chrome. Chrome fails to load the client details.
I checked the requests made by angularjs application using fiddler. I found that there are two calls made my angularjs application to webAPI, even though in code there is only one call in code,
Following is the code used in angular app
return $http({
method: "GET",
withCredentials: true,
url: $rootScope.models.ServiceURL + "/ServicerClient?clientName=" + searchTextSmallLetters,
dataType: "json",
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
});
First request logged in Fiddler :
GET /PXTRAService.svc/ServicerClient?clientName=volvo HTTP/1.1
First request retunrs following error :
HTTP/1.1 401 Unauthorized
Next request logged in Fiddler has Security section in request header:
GET /PXTRAService.svc/ServicerClient?clientName=volvo HTTP/1.1
Second request retunrs the expected result.
Same scenario is occuring in IE, but IE angular application redeners the fetched results correctly.
Is there any way to fix this issue in chrome?

Angular HTTP request blocked - Showing mixed content

Angular HTTP request is blocked - Showing mixed content.
But when i'm accessing through browser URL, the content is showing.
The angular code is:
$http.post('http://crms.ttteamthoi.in/get_timespent_br', {
'from': '01/11/2015',
'to': '25/11/2015'
}, {
"headers": {
"Content-Type": "application/json; charset=UTF-8"
}
})
.then(function(response) {
//code here
}
The console error showing is:
Mixed Content: The page at 'https://dash-thaidash.c9users.io/#/app/tonnage' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://crms.ttteamthoi.in/get_timespent_br'. This request has been blocked; the content must be served over HTTPS.
Is this angular specific?
It does not seem to be Angular specific. crms.ttteamthoi.in host is telling you that accepts only https requests, but you POST some data using http protocol. Try using https.
You can simulate http requests here.
Problem Solved.
Server is asp.net application without SSL. The call was from https://c9.io which is secure. That was the mixed content error.
Changing the server application to SSL & then enabling CORS for content type did the trick.

Angularjs: Passing along a token using $resource?

I am trying to pass along a token using headers with my $resource requests. Normally you can do the following
$http.defaults.headers.common
in the .config, but I am unaware of these when the application first bootstraps so I thought i would do the following... But its currently not passing my headers..
Currently the token is hard coded but once i have confirmed it working then it will come from a injected service that holds the token.
var resource = $resource('http://localhost:port/todos/:id', {
port:":3001",
id:'#id'
}, {
get: {
method: "GET",
headers: {
"Accept": "application/stuffs;version=3",
"Authorization": "Token token='xxxxxxxxx '"
}
},
update: {method: 'PUT'}
});
return resource;
If i check fiddler I don't see the accept or authorization headers in my request.
I do see the message in fiddler but none of the headers that i was expecting.
Am I missing something here?
Any ideas?
Thanks
First, there is nothing wrong with your client side code. It should work fine if you're not doing cross origin request (CORS - xhr request to a different host / port than what's serving your script). Here is a working non CORS plkr example with your code - you can verify that your custom headers are being sent: http://plnkr.co/edit/cEBGjvYBpXv1q1D323IL?p=preview
If you have to do a cross origin request you have to make sure that you're both using a browser that supports CORS (IE >= 10, latest Chrome or Firefox) and that your server code responds properly to the CORS preflight OPTION request. This article explains it pretty good: http://www.html5rocks.com/en/tutorials/cors/
I've created another plnkr example and got this working by setting up a server that responds the following (http://plnkr.co/edit/zJVhqJVSnApXGzGGxcN9?p=preview)
First - the preflight OPTION request
Request URL:http://localhost:8080/todos
Request Method:OPTIONS
Server response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,PUT
Access-Control-Allow-Headers: Authorization
Content-Length: 0
Next the "real" request
Request URL:http://localhost:8080/todos
Request Method:GET
Response (notice that access-control-allow headers are here also):
HTTP/1.1 200 OK
Content-Type: application/x-json; charset=UTF-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,PUT
Access-Control-Allow-Headers: Authorization
Content-Length: 13
Response body:
{"test":"OK"}
I looked into this by looking through the Angular code on GitHub. What I found out is that as of Angular 1.1.2, you can specify headers exactly as you have in your question. You can't specify headers in any version prior to 1.1.2.
As rGil suggested, make sure you are using the latest version of ngResource. It's very easy to upgrade Angular to 1.1.5, but not upgrade ngResource. In fact, I've done the very same thing with ngResource.
If you want be 100% sure, look for the following code inside ngResource (assuming you have the unminified code). This code loops over each property passed into your action (method and headers in your example) and copies them into an object (httpConfig). httpConfig is then passed into $http.
forEach(action, function(value, key) {
if (key != 'params' && key != 'isArray' ) {
httpConfig[key] = copy(value);
}
});
If you're missing this loop, you have an old version of ngResource.

Resources