jQuery.post() and redirect via ajax - javascript

I am using jQuery.post() to send data to the server, when the server sends data back to the client, the post() callback is invoked. I know that the server might response with the redirect header field ("Location").
currently, the redirect does not occur. what can be the reason?
is there any possibility to run a script before the redirect occur?
UPDATE:
enclosed a snipped code. i know that the POST method is accepted by the server, and that the server responds to the POST. somehow, always the error() is being invoked (it seems like it happends even before the response is accepted by the client\browswer).
what is wrong?
$(document).ready(function() {
$("#loginForm").submit(function() {
$.ajax({
type : "POST",
data : $("#loginForm :input").not("#loginBtn").serialize(),
url : "http://localhost/auth",
success : function(data, textStatus, jqXHR) {
alert("success");
alert(jqXHR.getResponseHeader("Location"));
},
error : function(jqXHR, textStatus, errorThrown) {
alert("error");
}
});
});
});

jquery.post() works by issuing an Ajax request. In an Ajax call, the PHP script works asynchronously (think of it as a background thread). Thus, the PHP script cannot redirect the client's browser. The way to go would be to have the PHP script responsd with the URL to redirect to, and redirect using javascript.
In your POST callback:
function(data){ //data will be the URL to redirect to, sent back by the PHP script
window.location = data;
}
EDIT
From Jquery documentation on jquery.ajax()
statusCode(added 1.5)Map
Default: {}
A map of numeric HTTP codes and functions to be called when the response has the corresponding code. For example, the following will alert when the response status is a 404:
$.ajax({
statusCode: {
404: function() {
alert('page not found');
}
}
});
If the request is successful, the status code functions take the same parameters as the success callback; if it results in an error, they take the same parameters as the error callback.

Please in redirect case get simple response without redirecting print any flag like "redirect" and and write client side redirect using
if(responce == 'redirect')
window.location = "Your url"
Do not redirect on server.
It will work.

If you perform an operation that results in a redirect, JQuery does not detect it. The browser handles it automatically behind the scenes, to create a seamless experience.

Related

How to redirect a user to a login page from a servlet? [duplicate]

This question already has answers here:
How should I use servlets and Ajax?
(7 answers)
Closed 5 years ago.
I am trying to redirect a user to the login page of the website from page A if at the time of the page load no login details are found in the session. I am using a servlet for the same.
From page A, I am making the most basic AJAX call at page load to my servlet as below:
$.ajax({
url: "/bin/website/protectedpage.html",
success: function(){
}
});
However, I have only been able to achieve the following results with the mentioned approaches:
1.
response.sendRedirect("/content/website/en/login.html");
resulting into an HTTP code 302 in response but no redirection actually happening. Also, there is nothing returned in the response body.
2.
ServletContext context= getServletContext();
RequestDispatcher rd= context.getRequestDispatcher("content/website/en/login.html");
rd.forward(request, response);
resulting into a Response code 200 returning the whole login page HTML in the response body but still not redirecting the user to the login page.
What am I missing? Please help me with the same. Thanks in advance.
$.ajax() performs an asynchrounous HTTP call to the server. Redirecting the call just from the server won't also redirect on the browser. You will have to handle the redirection after the ajax call on the front-end itself.
You can try something like this
$.ajax({
type: "POST",
url: URL,
data: reqBody,
dataType: "json",
success: function(data, textStatus) {
if (data.redirect) {
// Redirect here
window.location.href = data.redirect;
}
else {
// No redirection.
}
}
});
PS: Code block copied from here.
you can use window.location.replace("url") (simulate an HTTP redirect).
If ypu prefer, you can use window.location.href = "url". This is similar to click a link.
The function replace() does not keep the originating page in the session history, so the user can't get stuck in a never-ending back-button. For me, replace() is the best choice.
Would you have tried something like
function_name(funct) { return function(data) { if($("#myForm", data).size() > 0) top.location.href="login"; else funct(data); } }
for example
function sample(data, funct){
if($("#myForm", data).length > 0)
top.location.href="login.htm";//redirection
else
funct(data);
}
Then, when making the Ajax call we used something like:
$.post("myAjaxHandler",
{
param1: sam,
param2: kari
},
function(data){
sample(data, myActualCB);
},
"html"
);
all Ajax calls always returned HTML inside a DIV element that we use to replace a piece of the page. Also, we only needed to redirect to the login page.
We basically have an ISA server in between which listens to all requests and responds with a 302 and a location header to our login page.
Now check for status 302 as you have mentioned above that you are getting response 302
$(document).ajaxComplete(function(e, xhr, settings){
if(xhr.status === 302){
var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
window.location.replace(loginPageRedirectHeader); //check for location header and redirect...
}
});

Automatic redirection on 302 status

$.ajax({
type: "POST",
url: "/someurl",
data: $("#send_application_number").serialize(),
success: function(response, textStatus, request) {
#responseType = request.getResponseHeader('Location')
$("#captchapopup").foundation("reveal","open")
$("#viewstate").val(response['viewstate'])
$("#eventvalidate").val(response['eventvalidate'])
$("#appl_num").val(response['appl_num'])
#loc = getcaptchaimage(response['viewstate'], response['eventvalidate'])
loc = '/anotherurl?viewstate=' + response['viewstate'] + '&eventvalidate=' + response['eventvalidate']
$("#captchaimage").attr('src', loc)
},
error: function() {
alert("Could not get response to session login request");
}
});
As you can see this is a script for running a modal pop-up to display a captcha. BUT, I may redirect to another url as well, instead of displaying the modal, which is why I sent a 302 redirect (and a url of course) from back-end assuming it would redirect automatically. It did , BUT the rest of the script also executed as well, which brought it back to the modal.
How do I achieve an if-else kind of redirect? That if 'Location' is present, redirect and don't execute the rest of the script?
AJAX is a request in the background, and that means you can not redirect the “foreground” (browser UI) from there via HTTP.
Use location.href="…" to redirect from within your success handler. (Have your server send it a value that it can base that decision on.)

how do i redirect to any other page for json request type?

my application redirects the user to the login page whenever there is no session. But for Ajax request this redirecting is not happening.
I need to handle this redirection issue for all ajax calls in the application.
I were doing similar thing on Zend/PHP project. Unfortunately, I'm not familiar with Java and there I can suggest only basic direction.
By default, XMLHttpRequest execute redirects. So if you do a redirect during ajax request, XMLHttpRequest will execute it without letting you know that redirect happened at all. At least I found no way to catch such situation and handle it somehow. Because of that, on server side I override a redirect method. Suppose you can do something like that in Java too. Once request came from ajax (you can add a some specific header to your ajax request and check it on server) you can return a header different from Location header. For instance, New-Location, and do no actual redirect. Just stop request execution.
On client side you can use jQuery.ajaxSetup to configure global handler for all ajax requests at once.
Here is how you can add a header to all requests with .ajaxSetup:
$.ajaxSetup({
headers: {
XHTTPRequest: 'true'
}
});
Additionally you can set a global ajaxSuccess and ajaxError handlers. They will be executed before any success/error handler of a separate ajax request. In global ajax success you can take a header from xhr object passed as a third parameter to callback function and do a redirect:
var newLocation = xhr.getResponseHeader("New-Location");
if(newLocation)
document.location = newLocation;
Basically, you can return special object instead of header or find some other way to pass a new location to your ajaxSuccess callback.
You can use window.location in AJAX success block to redirect the user to the target page.
The way i do it:
At the server side:
define('BASE_URL','http://www.yourdomain.com');
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){
// if it's an ajax request
$json['success'] = 1;
$json['redirect'] = BASE_URL.'/logout';
echo json_encode($json);
}else{
// if it's an non ajax request
}
At the client side using jquery:
$.ajax({
type: "POST",
url: 'www.yourdomain.com',
data: {test: 1},
complete: function(e, xhr, settings){
switch(e.status){
case 500:
alert('500 internal server error!');
break;
case 404:
alert('404 Page not found!');
break;
case 401:
alert('401 unauthorized access');
break;
}
}
}).done(function( data ) {
var obj = jQuery.parseJSON(data)
if (obj.success == 1){
var url = obj.redirect;
location.href = url;
}
});

Salesforce - success handler for $.ajax call

I have a form that I have been submitting to Salesforce with standard form submit action. By default, you can tell Salesforce to redirect you to a given URL after the POST has completed.
I no longer wish to be redirected since I have other activities on the form page. No problem, my page is already using jQuery so I can use the handy $.ajax utility like this:
$('#wrapper').on('click', '#formsubmit', function(e) {
e.preventDefault();
var formData = $('#subForm').serialize();
$.ajax({
type: "POST",
url: "https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8",
data: formData,
success: function() {
console.log('success!'); // or not!
},
error:function (xhr, ajaxOptions, thrownError){
console.log(xhr.status); // 0
console.log(thrownError); // empty
}
});
});
In my misguided brain, I imagined that Salesforce would return my good ol' redirect, which would count as a "success" that I can just discard/ignore. Misguided indeed!
I can see a 200 OK result (which usually means "success") but the success callback isn't tripped.
The lead is added to the Salesforce database
Inspecting the content of what's returned shows zero; there is no content in the response.
The error callback IS being tripped (despite the 200 OK) but maybe due to intentionally not redirecting it is seen as a "resource not available"? (therefore my status code is 0, and there is no content in the thrownError?).
Any advice on identifying this as a successful POST so that I can trigger additional actions in a callback? I don't want to TOTALLY ignore the response, or I could end up in a scenario in which I'm acting on a failed POST as if it was successful. I need to capture the success somehow.
It occurred to me that it could be a cross-site scripting issue as well, but since the application doesn't exchange data in JSONP, I'm not sure how to get around that (and I'm not sure how to identify it in the first place).
Few things here:
1) The redirect response being sent by salesforce's API is most likely being interpreted as an error code.
2) The response code of the subsequent page (after the redirect) is 200 OK, from the sound of it.
3) It is not possible to do a POST request using JSONP. This is a limitation of JSONP; which is not actually an AJAX request, but an HTTP GET request wrapped inside of a dynamically generated script tag. Also, JSONP only works if the request yields an HTTP response of 200 OK.
I would recommend using your own server-side intermediary to handle your AJAX POST request. This will act as a proxy between your front-end app and salesforce's API. This will also allow you to better control the response being sent to your app.
var formData = $('#subForm').serialize();
var response = $.ajax({
type: "POST",
url: "https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8",
data: formData,
success: function() {
console.log('success!'); // or not!
},
error:function (xhr, ajaxOptions, thrownError){
console.log(xhr.status); // 0
console.log(thrownError); // empty
}
}).responseText;
where var response will contain the return value from your ajax call

AD FS 2.0 Authentication and AJAX

I have a web site that is trying to call an MVC controller action on another web site. These sites are both setup as relying party trusts in AD FS 2.0. Everything authenticates and works fine when opening pages in the browser window between the two sites. However, when trying to call a controller action from JavaScript using the jQuery AJAX method it always fails. Here is a code snippet of what I'm trying to do...
$.ajax({
url: "relyingPartySite/Controller/Action",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});
The issue is that AD FS uses JavaScript to post a hidden html form to the relying party.
When tracing with Fiddler I can see it get to the AD FS site and return this html form which should post and redirect to the controller action authenticated. The problem is this form is coming back as the result of the ajax request and obviously going to fail with a parser error since the ajax request expects json from the controller action. It seems like this would be a common scenario, so what is the proper way to communicate with AD FS from AJAX and handle this redirection?
You have two options.
More info here.
The first is to share a session cookie between an entry application (one that is HTML based) and your API solutions. You configure both applications to use the same WIF cookie. This only works if both applications are on the same root domain.
See the above post or this stackoverflow question.
The other option is to disable the passiveRedirect for AJAX requests (as Gutek's answer). This will return a http status code of 401 which you can handle in Javascript.
When you detect the 401, you load a dummy page (or a "Authenticating" dialog which could double as a login dialog if credentials need to be given again) in an iFrame. When the iFrame has completed you then attempt the call again. This time the session cookie will be present on the call and it should succeed.
//Requires Jquery 1.9+
var webAPIHtmlPage = "http://webapi.somedomain/preauth.html"
function authenticate() {
return $.Deferred(function (d) {
//Potentially could make this into a little popup layer
//that shows we are authenticating, and allows for re-authentication if needed
var iFrame = $("<iframe></iframe>");
iFrame.hide();
iFrame.appendTo("body");
iFrame.attr('src', webAPIHtmlPage);
iFrame.load(function () {
iFrame.remove();
d.resolve();
});
});
};
function makeCall() {
return $.getJSON(uri)
.then(function(data) {
return $.Deferred(function(d) { d.resolve(data); });
},
function(error) {
if (error.status == 401) {
//Authenticating,
//TODO:should add a check to prevnet infinite loop
return authenticate().then(function() {
//Making the call again
return makeCall();
});
} else {
return $.Deferred(function(d) {
d.reject(error);
});
}
});
}
If you do not want to receive HTML with the link you can handle AuthorizationFailed on WSFederationAuthenticationModule and set RedirectToIdentityProvider to false on Ajax calls only.
for example:
FederatedAuthentication.WSFederationAuthenticationModule.AuthorizationFailed += (sender, e) =>
{
if (Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
{
e.RedirectToIdentityProvider = false;
}
};
This with Authorize attribute will return you status code 401 and if you want to have something different, then you can implement own Authorize attribute and write special code on Ajax Request.
In the project which I currently work with, we had the same issue with SAML token expiration on the clientside and causing issues with ajax calls. In our particular case we needed all requests to be enqueud after the first 401 is encountered and after successful authentication all of them could be resent. The authentication uses the iframe solution suggested by Adam Mills, but also goes a little further in case user credentials need to be entered, which is done by displaying a dialog informing the user to login on an external view (since ADFS does not allow displaying login page in an iframe atleast not default configuration) during which waiting request are waiting to be finished but the user needs to login on from an external page. The waiting requests can also be rejected if user chooses to Cancel and in those cases jquery error will be called for each request.
Here's a link to a gist with the example code:
https://gist.github.com/kavhad/bb0d8e4a446496a6c05a
Note my code is based on usage of jquery for handling all ajax request. If your ajax request are being handled by vanilla javascript, other libraries or frameworks then you can perhaps find some inspiration in this example. The usage of jquery ui is only because of the dialog and stands for a small portion of the code which could easly be swapped out.
Update
Sorry I changed my github account name and that's why link did not work. It should work now.
First of all you say you are trying to make an ajax call to another website, does your call conforms to same origin policy of web browsers? If it does then you are expecting html as a response from your server, changedatatype of the ajax call to dataType: "html", then insert the form into your DOM.
Perhaps the 2 first posts of this serie will help you. They consider ADFS and AJAX requests
What I think I would try to do is to see why the authentication cookies are not transmitted through ajax, and find a mean to send them with my request. Or wrap the ajax call in a function that pre authenticate by retrieving the html form, appending it hidden to the DOM, submitting it (it will hopefully set the good cookies) then send the appropriate request you wanted to send originally
You can do only this type of datatype
"xml": Treat the response as an XML document that can be processed via jQuery.
"html": Treat the response as HTML (plain text); included script tags are evaluated.
"script": Evaluates the response as JavaScript and evaluates it.
"json": Evaluates the response as JSON and sends a JavaScript Object to the success callback.
If you can see in your fiddler that is returning only html then change your data type to html or if that only a script code then you can use script.
You should create a file anyname like json.php and then put the connection to the relayparty website this should works
$.ajax({
url: "json.php",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});

Categories

Resources