Cannot read response headers for CORS request with jQuery - javascript

I have a working cross-domain web service call where I get my payload back, but I cannot read the headers in the response. Chrome can show me the headers in the request fine, but they are not available in jQuery's success handler.
var data_obj = { "userName": "myUser", "password": "000000" }
$.ajax({
type: "POST",
url: 'https://localhost:8443/AuthService.svc/auth',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data_obj),
dataType: "json",
success: function(data, textStatus, jqXHR) {
console.log(jqXHR.getAllResponseHeaders());
}
});
The only thing that gets logged to the console is:
Content-Type: application/json; charset=utf-8
Here is what Chrome is reporting for the OPTIONS and POST response headers, note that I am attempting to expose Foo and Authorization via Acccess-Control-Expose-Headers:
OPTIONS
Acccess-Control-Expose-Headers:Content-Type, Foo, Authorization
Access-Control-Allow-Headers:Content-Type, Foo, Authorization
Access-Control-Allow-Methods:POST, PUT, DELETE
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Content-Length:0
Date:Mon, 20 Jul 2015 16:26:00 GMT
Foo:Bar
POST
Acccess-Control-Expose-Headers:Content-Type, Foo, Authorization
Access-Control-Allow-Headers:Content-Type, Foo, Authorization
Access-Control-Allow-Origin:*
Authorization: custom_access_token = some_token
Content-Length:36
Content-Type:application/json; charset=utf-8
Date:Mon, 20 Jul 2015 16:26:00 GMT
Foo:Bar
Can anyone figure out why I can only access the Content-Type header in my success callback?
Update
Note I refactored the above to use XMLHttpRequest, the behaviour persists.

There is a typo in your response header:
Acccess-Control-Expose-Headers:Content-Type, Foo, Authorization
You have three "c" in "access". I admit it took too long for me to notice too.
While I don't have Chrome (only Firefox), I replicated your request as closely as I could and fixing the typo returned this:
Foo: Bar
Authorization: custom_access_token = some_token
Content-Type: text/html; charset=utf-8
Addendum
Seeing that another answer is advising you to use withCredentials, if for some reason you did that, remember that Access-Control-Allow-Origin must match the Origin request header that your browser will likely set on its own and it can not be a wildcard. I'm putting this here to avoid another possible issue.
The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
See the Mozilla docs

Related

Angularjs - Incorrect json format under Content-Type-application/json

Purpose:
I (a javascript beginner) am trying to perform a Rest API call to a web-server (Splunk) get data of content-type json. Call is initiated by angularjs based webApp, the problematic code snippet is posted below. The problem is investigated using firebug and the response & header information is mentioned below.
Angular Code Snippet:
$scope.onClickButton = function (button) {
$http({
method: 'POST',
url: 'https://localhost:8089/servicesNS/admin/search/search/jobs/export',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Splunk ' + $scope.sessionKey
},
data: {search: button.query, output_mode: 'json'}
}).success(function (response) {
alert("Success");
}).error(function (response) {
alert("error");// alerted error
alert(response); // alerts 'undefined'
});
};
Response Object (captured by firebug)
{"preview":false,"offset":0,"result":{"_serial":"0", "_sourcetype":"mylogger", "splunk_server":"mohit-PC"}}
{"preview":false,"offset":1,"result":{"_serial":"1", "_sourcetype":"mylogger", "splunk_server":"mohit-PC"}}
{"preview":false,"offset":2,"result":{"_serial":"2", "_sourcetype":"mylogger", "splunk_server":"mohit-PC"}}
...
Response Header
Access-Control-Allow-Head... Authorization
Access-Control-Allow-Meth... GET,POST,PUT,DELETE,HEAD,OPTIONS
Access-Control-Allow-Orig... *
Cache-Control no-store, no-cache, must-revalidate, max-age=0
Connection Keep-Alive
Content-Type application/json; charset=UTF-8
Date Tue, 02 Dec 2014 13:00:34 GMT
Expires Thu, 26 Oct 1978 00:00:00 GMT
Server Splunkd
Transfer-Encoding chunked
Vary Authorization
access-control-allow-cred... true
x-content-type-options nosniff
x-frame-options SAMEORIGIN
Firebug Error
Error: JSON.parse: unexpected non-whitespace character after JSON data at line 2 column 1 of the JSON data fromJson#angular.js:1054:9
.
Questions
Q1. The status of response is - 200 OK, then why the error is thrown? Though it is apparent that the response text does not represent a json object or an array of json objects. The [] and commas are absent. The server cannot be configured to respond with a proper formatted data. It seems angular does a format verification and throws exception. Can this verification be avoided/bypassed?
Q2. Even though the error occurred, why the response object is 'undefined' in http.error method? If it were not, I could do string manipulations as a work around.

AngularJS $http returns status code 0 from failed CORS request

Okay, I've looked all over for this. Basically we're using $http request that ARE cross domain requests. Our server allows the domain and when a request returns 200, everything is OK. However, anytime our server returns an error, 500, 401, whatever, Angular thinks it's a CORS issue.
I debugged the response with Fiddler to verify my server IS returning a 500, yet Angular chokes on it.
Here's the request:
var params = {
url: "fakehost/example",
method: 'GET',
headers: {
"Authorization": "Basic encodedAuthExample"
}
};
$http(params).then(
function (response) { // success
},
function (error) { // error
// error.status is always 0, never includes data error msg
});
Then in the console, I will see this:
XMLHttpRequest cannot load fakehost/example. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'mylocalhost:5750' is therefore not allowed access.
Yet, in fiddler, the true response is:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 26 Aug 2014 12:18:17 GMT
Content-Length: 5683
{"errorId":null,"errorMessage":"Index was outside the bounds of the array.","errorDescription":"Stack trace here"}
I'm on AngularJS v1.2.16
I think I found an answer, looks like you will have to inject in your asp.net pipeline the correct CORS headers, as mentioned here.

Ajax stops working after changing domain name in internet explorer 9

We are developing a mobile site using html5, jQuery(1.8.2) and jQuery mobile while making jQuery ajax calls (get and post).
After we changed our domain name, we are getting "access denied" for ajax calls on ie9.
We tried to include jquery.iecors.js. But still we are getting the same error.Is there any resolution for this?
Sample Code:
$.support.cors = true;
$.ajax({
cache: false,
async: true,
crossDomain: true,
timeout: 600000,
url: baseUrl + '/SmartTouch/restServices/PrefferedHotels',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + myencoded);
},
contentType: "application/x-www.form-urlencoded; (http://www.form-urlencoded;) (http://www.form-urlencoded;) charset=UTF-8",
success: function (data) {
alert("success");
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error!!::" + JSON.stringify(jqXHR));
alert('response: ' + jqXHR.responseText);
alert('code: ' + jqXHR.getResponseHeader('X-Subscriber-Status'));
alert("textStatus " + textStatus);
alert("errorThrown " + errorThrown);
}
});
Edited:
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + myencoded);
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.setRequestHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
},
contentType: "application/x-www.form-urlencoded; (http://www.form-urlencoded;) (http://www.form-urlencoded;) charset=UTF-8",
success: function (data) {
alert("success");
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error!!::" + JSON.stringify(jqXHR));
Request and Response headers in IE9:
Request:
Key Value
Request GET url HTTP/1.1
Accept text/html, application/xhtml+xml, */*
Accept-Language en-US
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding gzip, deflate
Proxy-Connection Keep-Alive
Host ("url")
Pragma no-cache
Cookie GUEST_LANGUAGE_ID=en_US; COOKIE_SUPPORT=true; __utmc=24444716; __utma=24444716.47018335.1379597653.1380274476.1380276859.17; __utmz=24444716.1379597653.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmb=24444716.6.10.1380276859
Response:
Key Value
Response HTTP/1.1 200 OK
Server Apache-Coyote/1.1
X-Powered-By Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Accept-Ranges bytes
ETag W/"64578-1380266616000"
Last-Modified Fri, 27 Sep 2013 07:23:36 GMT
Content-Type text/html
Date Fri, 27 Sep 2013 10:17:01 GMT
Content-Length 64578
Age 0
Via 1.1 localhost.localdomain
This kind of Content-Type looks strange:
application/x-www.form-urlencoded; (http://www.form-urlencoded;) (http://www.form-urlencoded;) charset=UTF-8"
I can imagine the IE has as problem with it.
Try the proper one:
application/x-www-form-urlencoded; charset=UTF-8
^-- notice: no dot!
It's also possible for the IE to have problems with the authorization.
Maybe myencoded is out of the scope or not filled correctly. Debug this variable and have a look at this question: Authorization through setRequestHeader
If you want the Ajax url to be hit from any domain, the server must send a response header Access-Control-Allow-Origin : * or Access-Control-Allow-Origin : your-domain if restricted only to your domain.Can you see these headers in response?
See this Microsoft article on CORS implementation on IE8 and IE9: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
Specifically they say two things:
No custom headers may be added to the request
and
No authentication or cookies will be sent with the request
And you mentioned in your comment:
Our problem is we are doing basic authorization and including following header: xhr.setRequestHeader("Authorization", "Basic " + myencoded); in our ajax call.But in ie9 we are getting access denied.Is there any way to include this header?
Unfortunately, the answer I'll have to give you is no, there is no way to include this header in IE8 or IE9. Microsoft designed it that way.
To get it to work with CORS on IE9 you'll have to convince the site you're connecting to to allow you to send authorization information some other way - maybe query params or post data.
If the site is not cooperative there's always the request proxy work-around where you request to a page on your server and you server forwards the request with the correct header etc.
You seem confident that the issue has nothing to do with the suggested jQuery bug (especially since you're using jquery.iecors.js) so I'll move right on.
What is the significance of the "edited" bit? Access-Control-Allow-Origin:* should be set on the response (i.e. server-side, as part of Apache/IIS/F5 configuration), not on the request. Edit: there is more information available on MDN; you could also use something like burp's tampering proxy to play with the headers if you don't have immediate access to config changes (pretty common in an enterprise environment)
Even if not an issue, #DanFromGermany is absolutely right - content-type does look strange. You shouldn't even have to set it manually, jQuery.ajax() has it correct by default.
You also seem concerned with setting the basic authentication header. Remember that myencoded value is just encoded (not encrypted), so you might as well skip the header and pass credentials in the URL: http(s)://username:password#www.example.com/
Moar edit:
Looking through those MDN docos above, this seems relevant:
By default, in cross-site XMLHttpRequest invocations, browsers will
not send credentials. A specific flag has to be set on the
XMLHttpRequest object when it is invoked.
Perhaps try adding xhr.withCredentials = true; to your beforeSend?
Important note: when responding to a credentialed request, server must specify a domain, and cannot use wild carding. The above example
would fail if the header was wildcarded as:
Access-Control-Allow-Origin: *. Since the Access-Control-Allow-Origin
explicitly mentions http://foo.example, the credential-cognizant
content is returned to the invoking web content.
This would invalidate previous advice of using an asterisk in the header (i.e. explicit domain is required)
If you were using windows based hosting?
Please check old configs for the IIS, if available,
there are security provisions which will allow content by its type,
add this response header <% Response.AddHeader("Access-Control-Allow-Origin","*") %> in your page also.
or refer the source link to MSDN for more details
I think you have updated this in edits but there are many things as its AJAX involved, and your IE9 may also one of the reason if you have changed security options and not default.
I think that should do, if not please reply
You can try this
<meta http-equiv="X-UA-Compatible" content="IE=Edge" >
It forces the browser the render at whatever the most recent version's standards are. For reference http://msdn.microsoft.com/en-us/library/ie/ms533876%28v=vs.85%29.aspx

ExtJS 4.2.1: Cannot retrieve HTTP Response headers upon Ext.ajax.request callback

I'm trying to read the headers of the coming response upon Ext.ajax.request.
Here it is the code:
Ext.Ajax.request({ url: 'http://localhost:3000/v0.1/login' ,
method: 'POST',
scope:this,
jsonData: {"_username":username,"_userpwd":password},
success: function(responseObject){
var headers = responseObject.getAllResponseHeaders();
console.info(headers );
Ext.destroy(Ext.ComponentQuery.query('#loginWindow'));
this.application.getController('SiteViewController').showView();
},
failure: function(responseObject){
alert(responseObject.status);
}
});
But the only header that it is printed out in console is:
Object {content-type: "application/json; charset=utf-8"}
All the other headers are missing, but they are present in the chrome inspector!!!
What am I missing? Thanks
Because you're probably doing a cross-domain request, you will only have headers explicitly exposed by the server. Same domain requests expose all the headers.
On the server side you have to add the header "Access-Control-Expose-Headers" with the exhaustive list of headers you want to expose, separated by a coma. In php it would look like this:
header("Access-Control-Expose-Headers: Content-length, X-My-Own-Header");
The headers will indeed be available through responseObject.getAllResponseHeaders() or something like responseObject.getResponseHeader('content-type').
More information about cross-domain requests and headers: http://www.html5rocks.com/en/tutorials/cors/
PS: Ace.Yin had the right answer, but I don't have enough reputation to simply comment.
i ran into the same issue and finally i found the solution here: http://www.html5rocks.com/en/tutorials/cors/
here is the part about the headers:
Access-Control-Expose-Headers (optional) -
The XMLHttpRequest 2 object has a getResponseHeader() method that returns the value of
a particular response header. During a CORS request, the getResponseHeader() method
can only access simple response headers.
Simple response headers are defined as follows:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
If you want clients to be able to access other headers, you have to use the
Access-Control-Expose-Headers header. The value of this header is a comma-delimited
list of response headers you want to expose to the client.
i have not verify it yet, but it seems on the right track :)

CORS / xhr.getRequestHeaders

Greetings,
I am trying to use CORS (http://www.w3.org/TR/2009/WD-cors-20090317/#access-control-allow-methods-header) for an application on Safari, and when I try to read the response headers from the XMLHTTPRequest, I only receive the Content-Type. None of the other quite standard headers gets through, and I cannot figure out how to get this to work.
Anyone would happen to know how to fix this issue? Could this be a WebKit bug?
Edit
here is the config i use with nGinx:
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers Cache-Control,Pragma,Date;
add_header Access-Control-Allow-Methods GET,POST;
In order for headers to be exposes to JS, you need to set the Access-Control-Expose-Headers header to a comma-separated list of headers you want to expose.
Unfortunately, this header is poorly supported. Mozilla only implemented it in Firefox 4, Webkit as of this moment still does not implement it. I am not sure about IE8 and above (google didn't turn up anything useful, and I don't have them around to test with myself).
(see also eg. Restrictions of XMLHttpRequest's getResponseHeader()? )
Have you verified that your server is actually emitting the Cache-Control, Pragma and Date headers? Perhaps set up a Wireshark trace on the client to see the actual HTTP headers that are being exchanged?
I've been in same situation yesterday. https://stackoverflow.com/users/713326/gijs gave you the right answer but there is another part that is specific to nginx that you have to take care.
"add header" is working only in the case where the response from a service is successful (200, 204, 301, 302 or 304). You have to do a custom build of nginx to include HttpHeadersMoreModule
(http://wiki.nginx.org/HttpHeadersMoreModule). After you have to replace add_header with more_set_headers.
Example:
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Credentials: false';
more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, HEAD, PUT, PATCH, DELETE';
more_set_headers 'Access-Control-Allow-Headers:Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization;
more_set_headers 'Access-Control-Expose-Headers: Location';
REQUEST:
$.ajax({
url: "http://localhost:8079/students/add/",
type: "POST",
crossDomain: true,
data: JSON.stringify(somejson),
dataType: "json",
success: function (response) {
var resp = JSON.parse(response)
alert(resp.status);
},
error: function (xhr, status) {
alert("error");
}
});
RESPONSE:
response = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")
return response

Categories