The steps of my application are:
a client chooses several files via checkboxes,
a request is formed with the files' identifiers,
a client downloads the archive via an iframe: (a server finds these files, zips them, and then response is formed containing the zip archive 's bytes)
Here is the code of the iframe:
function makeSaveFrame(urlToServer) {
var ifrm = document.createElement("IFRAME");
ifrm.setAttribute("style", "display:none;");
ifrm.setAttribute("src", 'urlToServer';
ifrm.style.width = "0px";
ifrm.style.height = "0px";
document.body.appendChild(ifrm);
}
The response's type and header:
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachments; filename=\"" + fileName + ".zip\"");
The problem is: if something goes wrong, I need to send a reason to a client. As far as I am concerned, an error message must be of JSONObject type.
[if an error occurs on the server I can change the content type of the response and send a JSONObject, but I don't know how to filter the response and even how to catch an event of receiving a response in the iframe]
Please, share an expirience on this issue.
UPDATE
if I send
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "testMessage");
the bad response response arrives, but try/catch block around the makeSaveFrame() method doesn't catch this.
UPDATRE
I've tried this
var uploadForm = document.createElement('form');
uploadForm.name = 'uploadForm';
uploadForm.setAttribute("style", "display:none;");
document.body.appendChild(uploadForm);
Ext.Ajax.request({
url: 'requestURL',
form: uploadForm.getForm().getEl(),
isUpload : true,
method: 'post',
failure : function() {
Ext.MessageBox.show({
title : 'title',
msg : 'message',
buttons : Ext.MessageBox.OK
});
}
});
but the isUpload parameter kills a failure callback. So that, when a server answers with the bad response response, no error handler (failure callback) presents.
Since you have updated you question and not using frame anymore to request the content, you can use jquery, it can be similar to your updated content in question (ExtJS4 part in the end) ,
$.ajax({
url: 'requestURL',
form: uploadForm.serialize(),
method: 'post',
error : function(jqXHR, textStatus, errorThrown) {
// you can check the jqXHR object properties & methods to check
// the response status and contentType
alert("An error occured.");
}
});
Hope this helps.For more options on Jquery AJAX request follow JQuery reference
P.S : you need to add additional jquery library files to your page.
Please see this arcticle.
It seems that one can manipulate a content after upload, so that it is possible to apply a handler on it. Unfortunately, I had 2 problems in it:
in IE, 2 windows open and the second one (iframe) doesn't close after downloading a file (in FF works perfectly)
When a response arrives, the content is always empty, and I can't estimate it.
The next idea is to get cookies from the response header (iframe). This solution seems rather promising...
Related
I've got a few similar POST request on a website. In one case, the request is working (data is stored on the server), but then, there's an unexpected redirect. I send/receive data using jQuery. On the backend, I use the PHP framework Laravel.
Let's say I'm on myapp.dev/clients/123. Then I click the store-data-button and data is sent to/received from the server (Let's assume $('#resubmission_note').val() === 'abc'):
// AJAX request
$('#store-data-button').on('click', function() {
let ajaxRequest = $.ajax({
url: '/resubmissions',
type: 'POST',
data: {
// An integer, some text, and a date
'client_id': $('#id').html(),
'resubmission_note': $('#resubmission_note').val(),
'resubmission_due_date': $('#resubmission_due_date').val()
}
});
ajaxRequest.done(function(returned_id) {
// Removed all code here for testing. Browser still redirecting.
});
});
But then the browser is redirected to myapp.dev/clients/123?resubmission_note=abc.
The network tab in Chrome devtools says
Name:123?resubmission_note=abc
Status: 200
Type: document
initiator: Other
There's data appended in the URL, that should only be the case with GET request, AFAIK. I checked whether some other JavaScript code might interfere, but couldn't find store-data-button or resubmission_note in any unexpected files.
Any advice on how to fix the problem or how to debug it?
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()
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()
I developed a website for my graduation however it still only one thing I have do. What I want is when the script is installed on a website I want to send the name of the website who has installed my script, also whenever there is an error I want to send it to my website so for example:
This website installed my script
www.security-dz.com/myscript
I want to see the path + website in an other file in other website. For example:
www.getlog.com/mylogs.php
The purpose of this is keep my customers update and give them support and see the errors that happen so I can fix them in next updates.
You might want to take a closer look at the JQuery docs for ajax requests, so you can use a secure http connection for logging. This javascript code basically describes a function that sends the errors in text-format to your server-side script. This script can in turn write the error description to a file on the server. I'd recommend using a DB instead; That way you can easily write a web-client that displays all reported errors (and filters and the other good stuff).
You can extract the origin url from the referer [sic] field in the ajax http get-request on the server.
(function () { // function operator, in case console doesn't exist
!console ?
(console = {}) : console;
!console.log ?
(console.log = function () { }) : console.log;
!console.info ?
(console.info = console.log) : console.info;
!console.error ?
(console.error = console.log) : console.error;
}());
// Uses JQuery
function reportError (errDesc) {
var path = "www.getlog.com/mylogs.php";
$.ajax({
url: path,
type: "GET",
async: true,
cache: false,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
crossDomain: true,
data: errDesc,
dataType: "jsonp",
error: function (req, type, errObj) {
console.error("Reporting error failed: " + type + "\nAt url: " + path + "\n" + errObj);
// In case you need to debug the error reporting function
},
succes: function (res) {
console.info("Reported error to server:\nRequest:" + errDesc + "\nResponse: " + res);
// extra error logging facility on client-side, invisible to most users
},
global: false // prevent triggering global ajax event handlers
});
return errDesc; // in case you want to reuse the errDesc
}
Code has been validated with jshint. Please let me know if there are still issues, because I didn't take the time to completely replicate your setup (setting up 2 different domains etc.)
Addendum: Some useful reading if you're having issues with cross-domain messaging, JSON is not a subset of javascript, Cross-origin resource sharing, JSONP.
What you could do is post both the name of the website that uses your script and the error code variable with AJAX through URL to your logging website, which will then get the variable and name from the URL and use these to add to your log.
You should, however, by using this tactic, also make use of some URL validation, otherwise this will leave you wide open to injection attacks.
it is easy when your script installed , get the site info and send by socket and http request with get method and then recive it on your server.
for errors, php has some method to control error logs so custom it.
I am playing with Google API in javascript. I managed to get a list of my contact with the following code :
$.ajax({
url: 'https://www.google.com/m8/feeds/contacts/default/full?access_token=' + access_token + '&alt=json',
method: 'GET',
error: function(error) {
alert('An error has occured during contact creation.');
},
success: function(data, status){
console.log(data);
}
});
I tried to add a contact by changing GET to POST and adding my contact data in the request body. But as soon as I add a data attribute, or change GET to POST, the server answers me the really annoying "No 'Access-Control-Allow-Origin" error.
Any idea?
I am following this documentation : https://developers.google.com/google-apps/contacts/v3/?csw=1#creating_contacts
Thanks a lot
It is possible to do this from the browser, although not obvious at all.
Based on this SO answer, we learn that there is method called gapi.client.request that can be used for this (instead of jQuery's $.ajax).
Accordingly, for editing we can do:
gapi.client.request({
method : 'PUT',
path:'m8/feeds/contacts/default/full/<contactId>/<editRevisionFromGET>',
body : {"version":"1.0","encoding":"UTF-8","entry": ...},
callback : function(data) {
console.log(data);
}
});
The important parts for editing in here are:
send back the entire entry you got before from a read
use the current ID given at the end of the URL in the entry.link element with relation type edit (or you'll get a HTTP Status 409 - Conflict)
Side note:
Notice that these requests actually are done to https://content.googleapis.com/ ...
From some quick tests, it seems you can do ?all? requests just to that URL instead of google.com, and then CORS issues disappear.