express.js res.header doesn't work after ajax call [duplicate] - javascript

So I've got this jQuery AJAX call, and the response comes from the server in the form of a 302 redirect. I'd like to take this redirect and load it in an iframe, but when I try to view the header info with a javascript alert, it comes up null, even though firebug sees it correctly.
Here's the code, if it'll help:
$j.ajax({
type: 'POST',
url:'url.do',
data: formData,
complete: function(resp){
alert(resp.getAllResponseHeaders());
}
});
I don't really have access to the server-side stuff in order to move the URL to the response body, which I know would be the easiest solution, so any help with the parsing of the header would be fantastic.

cballou's solution will work if you are using an old version of jquery. In newer versions you can also try:
$.ajax({
type: 'POST',
url:'url.do',
data: formData,
success: function(data, textStatus, request){
alert(request.getResponseHeader('some_header'));
},
error: function (request, textStatus, errorThrown) {
alert(request.getResponseHeader('some_header'));
}
});
According to docs the XMLHttpRequest object is available as of jQuery 1.4.

If this is a CORS request, you may see all headers in debug tools (such as Chrome->Inspect Element->Network), but the xHR object will only retrieve the header (via xhr.getResponseHeader('Header')) if such a header is a simple response header:
Content-Type
Last-modified
Content-Language
Cache-Control
Expires
Pragma
If it is not in this set, it must be present in the Access-Control-Expose-Headers header returned by the server.
About the case in question, if it is a CORS request, one will only be able to retrieve the Location header through the XMLHttpRequest object if, and only if, the header below is also present:
Access-Control-Expose-Headers: Location
If its not a CORS request, XMLHttpRequest will have no problem retrieving it.

var geturl;
geturl = $.ajax({
type: "GET",
url: 'http://....',
success: function () {
alert("done!"+ geturl.getAllResponseHeaders());
}
});

The unfortunate truth about AJAX and the 302 redirect is that you can't get the headers from the return because the browser never gives them to the XHR. When a browser sees a 302 it automatically applies the redirect. In this case, you would see the header in firebug because the browser got it, but you would not see it in ajax, because the browser did not pass it. This is why the success and the error handlers never get called. Only the complete handler is called.
http://www.checkupdown.com/status/E302.html
The 302 response from the Web server should always include an alternative URL to which redirection should occur. If it does, a Web browser will immediately retry the alternative URL. So you never actually see a 302 error in a Web browser
Here are some stackoverflow posts on the subject. Some of the posts describe hacks to get around this issue.
How to manage a redirect request after a jQuery Ajax call
Catching 302 FOUND in JavaScript
HTTP redirect: 301 (permanent) vs. 302 (temporary)

The underlying XMLHttpRequest object used by jQuery will always silently follow redirects rather than return a 302 status code. Therefore, you can't use jQuery's AJAX request functionality to get the returned URL. Instead, you need to put all the data into a form and submit the form with the target attribute set to the value of the name attribute of the iframe:
$('#myIframe').attr('name', 'myIframe');
var form = $('<form method="POST" action="url.do"></form>').attr('target', 'myIframe');
$('<input type="hidden" />').attr({name: 'search', value: 'test'}).appendTo(form);
form.appendTo(document.body);
form.submit();
The server's url.do page will be loaded in the iframe, but when its 302 status arrives, the iframe will be redirected to the final destination.

UPDATE 2018 FOR JQUERY 3 AND LATER
I know this is an old question but none of the above solutions worked for me. Here is the solution that worked:
//I only created this function as I am making many ajax calls with different urls and appending the result to different divs
function makeAjaxCall(requestType, urlTo, resultAreaId){
var jqxhr = $.ajax({
type: requestType,
url: urlTo
});
//this section is executed when the server responds with no error
jqxhr.done(function(){
});
//this section is executed when the server responds with error
jqxhr.fail(function(){
})
//this section is always executed
jqxhr.always(function(){
console.log("getting header " + jqxhr.getResponseHeader('testHeader'));
});
}

try this:
type: "GET",
async: false,
complete: function (XMLHttpRequest, textStatus) {
var headers = XMLHttpRequest.getAllResponseHeaders();
}

+1 to PleaseStand
and here is my other hack:
after searching and found that the "cross ajax request" could not get response headers from XHR object, I gave up. and use iframe instead.
1. <iframe style="display:none"></iframe>
2. $("iframe").attr("src", "http://the_url_you_want_to_access")
//this is my aim!!!
3. $("iframe").contents().find('#someID').html()

Related

X-Forecast-API-Calls http response header inclusion and usage [duplicate]

So I've got this jQuery AJAX call, and the response comes from the server in the form of a 302 redirect. I'd like to take this redirect and load it in an iframe, but when I try to view the header info with a javascript alert, it comes up null, even though firebug sees it correctly.
Here's the code, if it'll help:
$j.ajax({
type: 'POST',
url:'url.do',
data: formData,
complete: function(resp){
alert(resp.getAllResponseHeaders());
}
});
I don't really have access to the server-side stuff in order to move the URL to the response body, which I know would be the easiest solution, so any help with the parsing of the header would be fantastic.
cballou's solution will work if you are using an old version of jquery. In newer versions you can also try:
$.ajax({
type: 'POST',
url:'url.do',
data: formData,
success: function(data, textStatus, request){
alert(request.getResponseHeader('some_header'));
},
error: function (request, textStatus, errorThrown) {
alert(request.getResponseHeader('some_header'));
}
});
According to docs the XMLHttpRequest object is available as of jQuery 1.4.
If this is a CORS request, you may see all headers in debug tools (such as Chrome->Inspect Element->Network), but the xHR object will only retrieve the header (via xhr.getResponseHeader('Header')) if such a header is a simple response header:
Content-Type
Last-modified
Content-Language
Cache-Control
Expires
Pragma
If it is not in this set, it must be present in the Access-Control-Expose-Headers header returned by the server.
About the case in question, if it is a CORS request, one will only be able to retrieve the Location header through the XMLHttpRequest object if, and only if, the header below is also present:
Access-Control-Expose-Headers: Location
If its not a CORS request, XMLHttpRequest will have no problem retrieving it.
var geturl;
geturl = $.ajax({
type: "GET",
url: 'http://....',
success: function () {
alert("done!"+ geturl.getAllResponseHeaders());
}
});
The unfortunate truth about AJAX and the 302 redirect is that you can't get the headers from the return because the browser never gives them to the XHR. When a browser sees a 302 it automatically applies the redirect. In this case, you would see the header in firebug because the browser got it, but you would not see it in ajax, because the browser did not pass it. This is why the success and the error handlers never get called. Only the complete handler is called.
http://www.checkupdown.com/status/E302.html
The 302 response from the Web server should always include an alternative URL to which redirection should occur. If it does, a Web browser will immediately retry the alternative URL. So you never actually see a 302 error in a Web browser
Here are some stackoverflow posts on the subject. Some of the posts describe hacks to get around this issue.
How to manage a redirect request after a jQuery Ajax call
Catching 302 FOUND in JavaScript
HTTP redirect: 301 (permanent) vs. 302 (temporary)
The underlying XMLHttpRequest object used by jQuery will always silently follow redirects rather than return a 302 status code. Therefore, you can't use jQuery's AJAX request functionality to get the returned URL. Instead, you need to put all the data into a form and submit the form with the target attribute set to the value of the name attribute of the iframe:
$('#myIframe').attr('name', 'myIframe');
var form = $('<form method="POST" action="url.do"></form>').attr('target', 'myIframe');
$('<input type="hidden" />').attr({name: 'search', value: 'test'}).appendTo(form);
form.appendTo(document.body);
form.submit();
The server's url.do page will be loaded in the iframe, but when its 302 status arrives, the iframe will be redirected to the final destination.
UPDATE 2018 FOR JQUERY 3 AND LATER
I know this is an old question but none of the above solutions worked for me. Here is the solution that worked:
//I only created this function as I am making many ajax calls with different urls and appending the result to different divs
function makeAjaxCall(requestType, urlTo, resultAreaId){
var jqxhr = $.ajax({
type: requestType,
url: urlTo
});
//this section is executed when the server responds with no error
jqxhr.done(function(){
});
//this section is executed when the server responds with error
jqxhr.fail(function(){
})
//this section is always executed
jqxhr.always(function(){
console.log("getting header " + jqxhr.getResponseHeader('testHeader'));
});
}
try this:
type: "GET",
async: false,
complete: function (XMLHttpRequest, textStatus) {
var headers = XMLHttpRequest.getAllResponseHeaders();
}
+1 to PleaseStand
and here is my other hack:
after searching and found that the "cross ajax request" could not get response headers from XHR object, I gave up. and use iframe instead.
1. <iframe style="display:none"></iframe>
2. $("iframe").attr("src", "http://the_url_you_want_to_access")
//this is my aim!!!
3. $("iframe").contents().find('#someID').html()

JSONP Syntax Error

I'm writing a jQuery interface to use a couple of OData services created in SAP. The services is working ok, and are also being used by some other applications.
I've already searched and I'm mostly come across people who are saying it's a cross domain issue. The first thing I tried was to plain and simply do a cross domain ajax call:
$.ajax({
url : 'http://saphostname:8000/sap/opu/odata/sap/entityset/?$format=json',
crossDomain : true,
xhrFields {
withCredentials : true,
}
// .. success, statusCodes, whatever ..
})
The responses that came from this call were 200, and if I viewed the content in the developer tools I saw my json message as I would expect it to be in there, but none of my callback functions were being triggered.
Upon searching more, somebody suggested using $.getJSON(). This didn't work either. The error that kept coming back was 401, so I assumed it was a cross domain issue.
The last thing I stumbled upon was JSONP. The response is coming back with an OK status code, and once again if I view the body content I see my json string as I would expect it. The only problem is my browser says there is a syntax error in the response text.
All of my search results have brought up issues regarding cross domain requests, and errors resulting there-in. Maybe it is the issue, but because I'm getting the results back that I would expect in the responses, I'd have to assume that connectivity is no problem.
tl;dr: ajax cross-domain requests are successful but don't trigger callback functions and jsonp gives me a syntax error. I'm not sure where to keep looking.
You are trying to do a JSONP request to a JSON service. The way that the response is handled for a JSONP request is that it is executed, but executing a JSON response only evaluates it and discards it.
The crossDomain property only causes the request to act like a cross domain request, i.e. using JSONP, regardless if it's actually to a different domain or not.
You should specify dataType: 'json' in the properties, to keep it from using JSONP.
Alternatively, if the service also supports JSONP, you could change $format=json in the URL to $format=jsonp, and specify dataType: 'jsonp' in the properties.
Edit:
Another thing that you can try is to use a proxy that turns a JSONP request to a JSON request. I have set up such a proxy that you can use to test if you can get the right response:
$.get(
"http://jsonp.guffa.com/Proxy.ashx?url=" + escapeURIComponent("saphostname:8000/sap/opu/odata/sap/entityset/?$format=json"),
function(data) {
console.log(data);
},
"jsonp"
);
I already had a problem like this before and what helped me to solve the problem was using callbacks like these:
// Assign handlers immediately after making the request,
// and remember the jqXHR object for this request
var jqxhr = $.ajax( "example.php" )
.done(function() {
alert( "success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "complete" );
});
// Perform other work here ...
// Set another completion function for the request above
jqxhr.always(function() {
alert( "second complete" );
});
Now you can see which one is being triggered and debug the problem.

jQuery cross domain post redirect

I'm trying to use jQuery to POST a form to chargify. My "Net" tab shows a 302 redirect (in red indicating an error), but jQuery is throwing a 404 error. Is it possible to preform a x-domain, post, redirect request from the browser or will I need to use proxy?
$(function() {
var endpoint = "https://api.chargify.com/api/v2/signups"
$('#new_sub_form').on('submit', function(e){
e.preventDefault()
var jqxhr = $.ajax({
type: "POST",
url: endpoint,
crossDomain:true,
data: $('#new_sub_form').serialize(),
success: function(data, textStatus, request){
console.log(request.getResponseHeader('Location'));
},
error: function (request, textStatus, errorThrown) {
console.log(request.getResponseHeader('Location')); // Returns null
}
})
})//on('submit')
})//ready()
UPDATE (more info):
So I realized the 302 was redirecting me to a page that didn't exist on my server. Unfortunately once i fixed this, I still have an issue. From what I can tell, i POST to chargify, they then send a 302 back to the browser with the URI I specified. This URI is located on my server (localhost for now). Once the user is redirected my server parses the response and returns JSON. I tested the Response Header location via copy and paste into another tab and works fine.
Chargify is only offering https, while my localhost is http. Would this cause the error?!
HTTP Response
Ran into to a very similar problem the other day. However im using ASP.NET MVC4.
Its not enough if you use crossDomain:true u also need to add,
dataType: 'json or html depending on the return value',
xhrFields: {
withCredentials: true
},
You will also need to add these headers "Access-Control-Allow-Origin:"http://yourdomain.net" ,
Access-Control-Allow-Credentials:true" and maybe "Access-Control-Allow-Methods:GET,POST" in your case aswell to your RESPONSE.
Chargify Direct does not support ajax/CORS.
You should use a "transarent redirect", as they describe, which is basically a standard form post redirecting the user to Chargify, and they will redirect the user back again to the URL you specify in the payload. This means the user will briefly leave your site and return back to it.
<form method="post" action="https://api.chargify.com/api/v2/signups">
</form>
Docs: https://docs.chargify.com/chargify-direct-introduction

JQuery AJAX JSONP Invalid Label

I know this question has been asked, but I cannot get it working.
I execute the following AJAX request:
function dislikeMeme(memeId) {
$.ajax({
dataType: "jsonp",
url: "http://<url>.com/dislike/" + memeId,
data: {
u: "username",
p: "password"
},
jsonpCallback: 'successCallback'
});
}
function successCallback(data) {
alert("Test"); // Not firing because of previous 'Invalid label' error
};
Looking at firebug I see that the request was successful, but there is an Invalid Label error which fires the Error callback of the request. The response of the request is as follows:
{
"id":6220673,
"myScore":-1,
"msg":"Not loved"
}
I see that the parentheses are causing JavaScript to interpret the response as an object, but I know this is the format I am retrieving, isn't there anyway to parse this before it causes an error?
I also see that the URL of the page returning this information is:
http://<url>.com/dislike/123456?callback=successCallback&u=username&p=password&_123456789
Everything is working perfectly except this Invalid label error. Does anyone have any ideas?
Thanks in advance everyone
A server that can handle JSONP takes the callback paramater (can be different parameter depending on WS) and passes it in the response. So the response from the server should be:
successCallback({
"id":6220673,
"myScore":-1,
"msg":"Not loved"
})
If you don't have control over the server your only route is proxy. See my cross domain answer for information on getting around same origin policy.
What prevents me from using $.ajax to load another domain's html?

Cross domain POST query using Cross-Origin Resource Sharing getting no data back

I'm sending data cross domain via a POST request but the response isn't working, specifically, jQuery's success handler never gets called.
Stuff being used: Django, Apache, jQuery.
So, I set up a request rather similar to this:
$.ajax({
url: "http://somesite.com/someplace",
type: "POST",
cache: false,
dataType: "json",
data: { ... },
success: function( msg ) {
alert(msg);
},
});
As you well know, CORS allows me to respond to an OPTIONS query appropriately to say "Yes, you can POST to me". Which I'm doing. Firebug confirms I'm getting my 200 status code and that the return type is in fact application/json. However, Firebug also confirms that the success handler in the above is not being called.
For reference, my response to OPTIONS is:
elif request.method == "OPTIONS":
response = HttpResponse("")
response['Access-Control-Allow-Origin'] = "*"
response['Access-Control-Allow-Methods'] = "POST, GET, OPTIONS"
response['Access-Control-Allow-Headers'] = "X-Requested-With"
return response
In contrast, if I set up a complete: function()... handler it works.
So, question is: what's happening (or not) and why? I am getting data fine, I'd just like to be able to return the response.
Update: This fixes my issue on some browsers but since I don't have a complete definite explanation to this behaviour I'm leaving it open.
Ok, so I read the manual and what I understand of it, the algorithm applied is roughly this:
User agents may implement a preflight call. This is the OPTIONS request. The idea is that they make this request which gives them an answer with respect to the requested resource, which they are then supposed to cache. I'm not passing back a max-age field, so I suspect whilst success is being returned and the X-request allowed, there is nothing in the user agent's cache which permitted me to make it, so the default rules (isolate the request) are applied.
When you make the actual request, I believe the user agent is supposed to inspect the pre-flight cache for permissions. Without my max-age field, I believe it isn't finding these permissions. However, responding with the same headers on POST appears to allow Firefox and Google Chrome to view the response. Opera can not. IE remains untested at the moment.
I do not currently understand and it is not clear from the manual (to me at least) whether a CORS request should also answer with these headers in the request as well as the OPTIONS. I shall experiment with the Max-Age header and see what that allows or does not allow. However, I'm still short of some definite authoritative understanding on the issue so if there is someone on here who knows, I'm all ears.
Ok, so I believe the correct way to do things is this:
if request.method == "POST":
response = HttpResponse(simplejson.dumps(data),mimetype='application/json')
response['Access-Control-Allow-Origin'] = "*"
return response
elif request.method == "OPTIONS":
response = HttpResponse("")
response['Access-Control-Allow-Origin'] = "*"
response['Access-Control-Allow-Methods'] = "POST, OPTIONS"
response['Access-Control-Allow-Headers'] = "X-Requested-With"
response['Access-Control-Max-Age'] = "1800"
else:
return HttpResponseBadRequest()
This is based on the documentation I dug up from Mozilla on preflighted requests.
So, what I believe will happen is this:
If there's nothing in the preflight cache, OPTIONS is sent with X-Requested-With set to XMLHttpRequest I believe this is necessary to allow Javascript access to anything, along with an Origin header.
The server can examine that information. That is the security of CORS. In my case, I'm responding with "any origin will do" and "you're allowed to send the X-Requested-With thing". I'm saying that OPTIONS and POST are allowed and that this response should be cached for 30 mins.
The client then goes ahead and makes the POST, which was working before.
I modified the response originally to include Allow-Methods and Allow-Headers but according to the exchange in the above linked documentation this isn't needed. This makes sense, the access check has already been done.
I believe then that what happens is the resource sharing check described here. Basically, once said request has been made, the browser again checks the Allow-Origin field for validity, this being on the request such as POST. If this passes, the client can have access to the data, if not, the request has already completed but the browser denies the actual client side application (Javascript) access to that data.
I believe that is a correct summary of what is going on and in any case it appears to work. If I'm not right, please shout.
For any future searchers who may come across this posting, the following resource is the W3C 2008 working-draft which discusses CORS in-depth.
http://www.w3.org/TR/2008/WD-access-control-20080912/
As of the time of this posting, it should be noted that Chromium specifically, and probably all of WebKit has a bug which prevents the Access-Control-Max-Age header's value from being honored. Details on this can be found on the discussion page for Chromium Issue 131368. In summary - as of now, WebKit-based browsers will override whatever the server returns as a value here with 600 (10 minutes).
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
I don't think this is possible for security reasons. The only cross domain ajax calls which browsers allow, can be done using JSONP and these are exclusively GET requests.
This will work:
$.ajax({
url: "http://somesite.com/someplace",
type: "GET",
cache: false,
dataType: "JSONP",
data: { ... },
success: function( msg ) {
alert(msg);
},
});
This won't:
$.ajax({
url: "http://somesite.com/someplace",
type: "POST",
cache: false,
dataType: "JSONP",
data: { ... },
success: function( msg ) {
alert(msg);
},
});

Categories