This is a common scenario in most of today web apps.
Today's web applications heavily rely on json for client server communication. Because json is a totally text based standard it goes very well until we need to send anything which is not text, like pdf files and images. And it is not a good idea that you implement a separate module to transfer binary files, it will defeat the whole purpose of using json.
I my self struggled a lot to find a good solution for this. And I didn't found a strait forward and simple tutorial to handle binary files with json.
So I decided to write one. Please share your comments and suggestions so I can Improve it.
Theory:
As json only supports text so we have to convert binary file (pdf, image etc) in to a string. And then we can easily add it to a json field.
Code Example: In my example I am using java for server end but you can use your own tools and languages, Theory will remain same.
I am assuming that you are familiar with jsp-servlet development thats why I am leaving out unnecessary implementation details of J2EE application.
Required jar Files : commons-codec-1.5.jar
Server End:
//Servlet
public class GetPdfServlet extends HttpServlet
{
public void doPost(HttpServletRequest request,HttpServletResponse response )
{
doGet(request,response);
}
public void doGet(HttpServletRequest request,HttpServletResponse response )
{
PrintWriter pw = null;
try{
pw = response.getWriter();
ByteArrayOutputStream ba= loadPdf(“myFile.pdf”);
//Converting byte[] to base64 string
//NOTE: Always remember to encode your base 64 string in utf8 format other wise you may always get problems on browser.
String pdfBase64String =
org.apache.commons.codec.binary.StringUtils.newStringUtf8(org.apache.
commons.codec.binary.Base64.encodeBase64(ba.toByteArray()));
//wrting json response to browser
pw.println("{");
pw.println("\"successful\": true,");
pw.println("\"pdf\": \""+pdfBase64String+"\"");
pw.println("}");
return;
}catch(Exception ex)
{
pw.println("{");
pw.println("\"successful\": false,");
pw.println("\"message\": \""+ex.getMessage()+"\",");
pw.println("}");
return;
}
}
private ByteArrayOutputStream loadPdf(String fileName)
{
File file = new File(fileName);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = fis.read(buf)) != -1;) {
bos.write(buf, 0, readNum); //no doubt here is 0
}
} catch (IOException ex) {
ex.printStackTrace();
}
return bos;
}
}
Client End :
index.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Example</title>
<script type="text/javascript" src="/js/loadPdf.js"></script>
</head>
<body>
<div id='dataFormContainer'>
</div>
<form>
<input type='button' value='getPDF' onClick='getPdf()'>
</form>
</body>
</html>
LoadPdf.js
function getPdf()
{
var ax = getXMLHttpRequest();
ax.open('POST', "[your servlet url]",true);
ax.onreadystatechange=function()
{
if(ax.readyState==4 && ax.status==200)
{
var dataFormContainer = document.getElementById("dataFormContainer");
var response = eval("("+ax.responseText+")");
if(response.successful)
{
var url = "data:application/pdf;base64,"+response.pdf;
var _iFrame = document.createElement('iframe');
_iFrame.setAttribute('src', url);
dataFormContainer.appendChild(_iFrame);
}
}
}
ax.send();
}
NOTE: Always remember to encode your base 64 string in utf8 format at server end other wise you may always get problems on browser.
More on: http://rahulbudholiya.blogspot.com
Guddu Kumar
Web Front-End/UI Developer at Arowana Consulting Limited
Hello Sir, can you please help on this ..... <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>Example</title> </head> <body> <div id='dataFormContainer'> </div> <form> <input type='button' value='getPDF' onClick='getPdf()'> </form> <script> function getPdf() { var str = "Hello World!"; var enc = window.btoa(str); //var ax = 'SGVsbG8gV29ybGQh'; var response = enc; var dataFormContainer = document.getElementById("dataFormContainer"); var url = "data:application/pdf;base64,"+response+'.pdf'; var _iFrame = document.createElement('iframe'); _iFrame.setAttribute('src', url); dataFormContainer.appendChild(_iFrame); } </script> </body> </html>
1moRahul Budholiya
Module Lead at YASH Technologies, Founder at LunaPlena Apps
What is your issue?
1moFrancisco Javier Briceño Sanchez
Fullstack Java Developer
Thanks, your article was too usefull.
5moAmit Kumar Pandya
Looking for job in Android mobile development.
Hi Rahul Budholiya I am working in Android and sending data to php sevrer. I am selecting a file from my file manager, and converting that into base64 string. But while sending that string into my request (due to large size of string) my request is gettting distorted and not able to send the request to server. Would u mind giving suggestions and a bit-help from coding side too? Thanks in advance.
11moRahul Budholiya
Module Lead at YASH Technologies, Founder at LunaPlena Apps
Hi Amit, In case you are trying to send a file from a mobile device to a server this example is not for your scenario. You don't need to convert the file in to base 64 string. If you can't send the file at once then you need send it in parts. You can simply read the file in parts convert them to byte[] and transmit data blocks one by one to server, and you need to collect all the data blocks at the server end and recreate the file. You can refer this tutorial for inspiration http://www.baeldung.com/java-read-lines-large-file
11moBrian Elliott
Software Developer at LBA Ware
Hey Rahul, we are trying to send a base 64 encoded PDF back as the response to our web service, but, for some reason, the web service rejects it? We are using UTF-8 encoding, but do you have any insight as to why the response would be rejecting the base64 encoded PDF? Here's the classes we use encode it, using (BinaryReader reader = new BinaryReader(src)) { CryptoStream cs = new CryptoStream(dest, new ToBase64Transform(), CryptoStreamMode.Write); BinaryWriter writer = new BinaryWriter(cs);
1yRahul Budholiya
Module Lead at YASH Technologies, Founder at LunaPlena Apps
You need to share exact error details what web service giving you. One possible reason i can guess is may be the base64 string is too large, more than the web service is configured to handle.
1moFabio Xavier de Lima
Coordenador de projetos. Analise e Desenvolvimento de sistemas.
Hello, I did the same in my REST application written in PHP and it worked perfectly. 1. Send the data encoded in base64 ( $data = base64_encode($data); ) to REST. 2. Before writing the file, I decode ( $data = base64_decode($data); ). 3. Therefore, when the file is downloaded, it is already in the correct format.
2yRahul Budholiya
Module Lead at YASH Technologies, Founder at LunaPlena Apps
Good to know Fabio, thanks for sharing.
2yIvan Shapoval
Java Software Engineer – SDK.finance
Hi Rahul, this approach that you described. Is it used? I mean, It's suitable for real project, or it's only for example?
2yRahul Budholiya
Module Lead at YASH Technologies, Founder at LunaPlena Apps
Hi Ivan, Definitely you can use it in your application. For example if you want to show a list of items in the browser, you can get a list of json objects from backend containing the information about the individual item of the list. Now if you want to show thumbnails along with their information, you can simply include the thumbnail image in the json object as a field. It will make it very easy to handle the code. And also you are not dependent on the image url to show images on the browser because you have included the image in the json itself, so you are free from creating and maintain images on the disk(or any web service) to create urls, you can directly get images from database (or any other storage) and send them directly to the browser. There are as many benefits as you can think of. But having said that, you must take in to account, the size of payload. You can't just include any size of binary content in json, because it will increase the size of json response, so you must consider the memory requirement of your project. But in general purpose scenarios it is good to use. Even I have created a framework to handle all this work in one of my projects, and out of there I have created this tutorial. I hope it answers your question.
2y