Why threre is no way to download file using ajax request? - javascript

In our application we need to implement following scenario:
A request is send from client
Server handles the request and generates file
Server returns file in response
Client browser displays file download popup dialog and allows user to download the file
Our application is ajax based application, so it would be very easy and convenient for us to send ajax request (like using jquery.ajax() function).
But after googilng, it turned out that file downloading is possible only when using non-ajax POST request (like described in this popular SO thread). So we needed to implement uglier and more complex solution that required building HTML structure of form with nested hidden fields.
Could someone explain in simple words why is that ajax requests cannot be used to download file? What's the mechanics behind that?

It's not about AJAX. You can download a file with AJAX, of course. However the file will be kept in memory, i.e. you cannot save file to disk. This is because JavaScript cannot interact with disk. That would be a serious security issue and it is blocked in all major browsers.

This can be done using the new HTML5 feature called Blob. There is a library FileSaver.js that can be utilized as a wrapper on top of that feature.

That's the same question I'd asked myself two days ago. There was a project with client written using ExtJS and server side realisation was on ASP.Net. I have to translate server side to Java. There was a function to download an XML file, that server generates after Ajax request from the client. We all know, that it's impossible to download file after Ajax request, just to store it in memory. But ... in the original application browser shows usual dialog with options open, save and cancel downloading. ASP.Net somehow changed the standard behaviour... It takes me two day to to prove again - there is no way to download file by request usual way ... the only exception is ASP.Net... Here is ASP.Net code
public static void WriteFileToResponse(byte[] fileData, string fileName)
{
var response = HttpContext.Current.Response;
var returnFilename = Path.GetFileName(fileName);
var headerValue = String.Format("attachment; filename={0}",
HttpUtility.UrlPathEncode(
String.IsNullOrEmpty(returnFilename)
? "attachment" : returnFilename));
response.AddHeader("content-disposition", headerValue);
response.ContentType = "application/octet-stream";
response.AddHeader("Pragma", "public");
var utf8 = Encoding.UTF8;
response.Charset = utf8.HeaderName;
response.ContentEncoding = utf8;
response.Flush();
response.BinaryWrite(fileData);
response.Flush();
response.Close();
}
This method was called from WebMethod, that, in turn, was called from ExtJS.Ajax.request. That's the magic. What's to me, I've ended with servlet and hidden iframe...

you can do this by using hidden iframe in your download page
just set the src of the hidden ifame in your ajax success responce and your task is done...
$.ajax({
type: 'GET',
url: './page.php',
data: $("#myform").serialize(),
success: function (data) {
$("#middle").attr('src','url');
},
});

Related

How to download an attachment from an AJAX request?

I am developing a web application which uses a .NET MVC back end and HTML with JavaScript and AJAX on the front end.
One page has a feature where the page makes an AJAX call to the .NET controller which then returns a JSON object. Based on the contents of this object, the browser downloads a PDF file. This is implemented so that the same .NET controller has another method which returns a stream, and the JavaScript code then makes a full page request (not an AJAX call in this case) to that method, which causes the browser to offer to view or save the PDF file.
However, this seems like extra work, particularly since the PDF file is already available when the first AJAX call returns. I could just as easily dump its contents into the returned JSON object, encoded in Base64 if necessary. But my question is, how can I then trigger the download in the browser in this case?
Within your ajax callback, create an <a> tag with the href attribute set to the base64 string and then click on the tag.
.then((response) => {
var pdf = response.data;
if(!pdf) { return; }
var a = document.createElement("a");
a.href = `data:application/pdf;base64,${pdf}`;
a.download = "filename.pdf";
a.click();
})
Although I would recommend twitching your controller to make it return the pdf file directly with Content-Type set to application/pdf and replace the ajax request with a simple JavaScript statement like window.location="/api/pdf/username"

JS AJAX to post generated file as PDF to server directory

I have a complex table generated via javascript that I'd like to save as PDF on the server. I've looked around at the pdf generation libraries and they all seem to be limited in terms of style, fonts, etc (that's what I meant by 'complex'). The table can be download client side as PDF or printed.
Let's say my function that generates the form to be printed is reportBody(data); - is there a way I can use AJAX to send the document as PDF to a php file that will save it server-side instead of downloading it client-side? The reportBody(data) is a collection of other variables, function calls etc.
So basically the question is - since we can generate a PDF file client-side, can we POST it (the pdf) via ajax to the server?
Short answer is Yes. Your provided information is still limited as it's not clear what is ran in the reporBody(data) but most PDF libraries on client side are able to give you the PDF file as base64 encoded data in form of a string.
You can then simply send that string to the server and save that as a PDF file.
A simple implementation will be something like this:
// I have used jQuery for convenience but you can use any lib or Vanilla JS
var saveData = $.ajax({
type: 'POST',
url: "url-to-the-php-script",
data: { pdfData: 'base64StringDataHere'},
dataType: "JSON",
success: function(resultData) { alert("Save Complete") }
});
Then on server side, do something like this:
$pdfData= $_POST['pdfData'];
file_put_contents('filename.pdf', base64_decode($pdfData));
Yes, there are a lot of ways. One would be, if you have html code in your reportBody(data); you could:
Send the html to a php file via ajax
in this php you could use https://wkhtmltopdf.org/ to generate a pdf file
In the client side you could point to that pdf generated

Saving a text file on server using JavaScript

Is it possible to save text to a new text file using JavaScript/jQuery without using PHP? The text I'm trying to save may contain HTML entities, JS, HTML, CSS and PHP scripts that I don't want to escape or use urlencode!
If it's only can be achieved using PHP how can I pass the text to PHP without encoding it?
You must have a server-side script to handle your request, it can't be done using javascript.
To send raw data without URIencoding or escaping special characters to the php and save it as new txt file you can send ajax request using post method and FormData like:
JS:
var data = new FormData();
data.append("data" , "the_text_you_want_to_save");
var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new activeXObject("Microsoft.XMLHTTP");
xhr.open( 'post', '/path/to/php', true );
xhr.send(data);
PHP:
if(!empty($_POST['data'])){
$data = $_POST['data'];
$fname = mktime() . ".txt";//generates random name
$file = fopen("upload/" .$fname, 'w');//creates new file
fwrite($file, $data);
fclose($file);
}
Edit:
As Florian mentioned below, the XHR fallback is not required since FormData is not supported in older browsers (formdata browser compatibiltiy), so you can declare XHR variable as:
var xhr = new XMLHttpRequest();
Also please note that this works only for browsers that support FormData such as IE +10.
It's not possible to save content to the website using only client-side scripting such as JavaScript and jQuery, but by submitting the data in an AJAX POST request you could perform the other half very easily on the server-side.
However, I would not recommend having raw content such as scripts so easily writeable to your hosting as this could easily be exploited. If you want to learn more about AJAX POST requests, you can read the jQuery API page:
http://api.jquery.com/jQuery.post/
And here are some things you ought to be aware of if you still want to save raw script files on your hosting. You have to be very careful with security if you are handling files like this!
File uploading (most of this applies if sending plain text too if javascript can choose the name of the file)
http://www.developershome.com/wap/wapUpload/wap_upload.asp?page=security
https://www.owasp.org/index.php/Unrestricted_File_Upload
If you still want to work in JavaScript and avoid PHP, CGI, and things like that, it's no longer true that you can't do server side scripts with JavaScript.
With Node.js, you can do server side JavaScript. Of course, you have to have a server than can run a Node.js server. But once you get it up and running, you can write the server script to accept a JSON formatted string from your client side scripts Then, based on that JSON string received, the server side script could create and save files. Of course, you want to make sure you write secure code, check what is being sent to your server and verify it's not malicious before creating the files and saving them. You also probably want to stagger timing and pause between files to ensure you're not susceptible to a DDOS attack, either.

Load XML content in javascript application

I develop a javascript application which display data from xml with charts and lists.
For now I put some sample files onto the server's directory that I load with :
$.ajax({ type: 'GET', url: 'data/default.xml', dataType: 'xml', ...})
The Xml files can be very heavy so when one of them is loaded I put the data in an IndexedDB.
In a second time I would like to let the visitor loads its own xml file by giving the filepath of the xml (f.i. : /home/user/sample.xml). I do not want to upload this file onto the server because I do not need it and it could be too big. But I do want to load those data in the IndexedDB and let the app displays data without any call to the server.
I do not know if browsers could work this way?
If they could, how can I do such a trick?
You can't use Ajax to get data from a file on the client system, but in sufficiently modern browsers you can use the File API. MDN has a guide to the File API that is friendlier then the specification.

Reading local XML file with javascript

I am new to HTML/Javascript, as well as coding in general so bear with me :). I am trying to create a "Spot the Difference" game in html5 using javascript. Everything is local (on my machine). I have two pictures, of the same size, one with differences. To generate data about the clickable fields, I have a java program that reads both of the images and outputs all of the positions in which pixels are different into a XML file. My plan was to then use this XML file with my javascript to define where the user could click. However, it appears (correct me if I'm wrong) that javascript cannot read local XML files for security reasons. I do not want to use an ActiveXObject because I plan on putting this onto mobile devices via phone gap or a webkit object. Does anyone have a better approach to this problem, or perhaps a way to read local XML files via javascript? Any help would be greatly appreciated, thanks.
If you are planning to put this into a smart phones (iOS and Android) and read local files, I have done similar things with JSON (yes, please don't use XML).
Convert your output to JSON
Put this as part of your application package. For example, in Android, I put it as part of the .apk in /appFiles/json
Create a custom content provider that would read the local file. I create mine as content:// but you create whatever scheme you want. You could leverage android.content.ContentProvider in order to achieve custom URL Scheme. iOS has its own way to create custom scheme as well. The implementation simply read your local storage and give the content
To read it from Javascript, I simply call ajax with the custom scheme to get the json file. For example content://myfile/theFile.json simply redirect me to particular directory in local storage with /myfile/theFile.json appended to it
Below is the sample to override openFile() in the ContentProvider
public ParcelFileDescriptor openFile (Uri uri, String mode) {
try {
Context c = getContext();
File cacheDir = c.getCacheDir();
String uriString = uri.toString();
String htmlFile = uriString.replaceAll(CUSTOM_CONTENT_URI, "");
// Translate the uri into pointer in the cache
File htmlResource = new File(cacheDir.toString() + File.separator + htmlFile);
File parentDir = htmlResource.getParentFile();
if(!parentDir.exists()) {
parentDir.mkdirs();
}
// get the file from one of the resources within the local storage
InputStream in = WebViewContentProvider.class.getResourceAsStream(htmlFile);
// copy the local storage to a cache file
copy(in, new FileOutputStream(htmlResource));
return ParcelFileDescriptor.open(htmlResource, ParcelFileDescriptor.MODE_READ_WRITE);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
I hope it helps
I would suggest modifying your java program to output a JSON formatted file instead of XML. JSON is native to JavaScript and will be much simpler for you to load.
As for actually loading the data, i'm not sure what the best option is as you say you want to evenutally run this on a mobile device. If you were just making a normal website you could setup a web server using either Apache or IIS depending on your OS and put the files in the document root. Once you've done that you can load the JSON file via Ajax, which can easily be googled for.
Not sure if this helps any.
Since this is a local file, you can do this with jQuery
$.ajax({
type: "GET",
url: "your.xml",
dataType: "xml",
success: function(xml){
///do your thing
}
});
http://api.jquery.com/jQuery.ajax/

Categories

Resources