How to download a file from SharePoint using Ajax from html


Recently I was able to help someone who was getting a corrupt file when trying to download from SharePoint Online through AJAX call.

He was able to download TEXT files successfully using the existing code, but it didn’t work for PDF or Word or Excel documents.

<script type="text/javascript">
	window.onload = () => {
		let code = '{!ACCESS_TOKEN}';   
		let extension = '{!extension}';

		//make a ajax callout
		$.ajax({
			url: "https://<YourSharePointSite>.sharepoint.com/_api/Web/GetFileByServerRelativePath(decodedurl='/DocLibrary/pdf_file.pdf')/$value", 
			type: 'get',  
			contentType: true, 
			processData: false, 
			headers: { accept: 'application/json',
					  "Authorization": "Bearer "+code,
					 },
			success: function(response){
				alert('success response'+response)
				var a = document.createElement('a');
				var binaryData = [];
				binaryData.push(response);
				var url = window.URL.createObjectURL(new Blob(binaryData),{type: "application/octet-stream"});
			   
				a.href = url;
				a.download = 'pdf_file.pdf';
				document.body.appendChild(a);
				a.click();
				a.remove();
				window.URL.revokeObjectURL(url);
			},
		});
	}
</script>

He did try to add responseType :’arraybuffer’ or responseType :’blob’, or use ‘binaryStringResponseBody : true’, but neither of them have helped to open the downloaded content as PDF successfully.

He was able to get the response back from SharePoint online, but it was not recognized as intended content type, i.e. PDF. In console it looked like above.

To fix this we had to force the stream to be treated and parsed as ‘text/plain’, and it worked beautifully!!

Here is the modified code, which has worked:

<script type="text/javascript">
window.onload = () => {
	let code = '{!ACCESS_TOKEN}';   

	$.ajax({
		url: "https://<YourSharePointSite>.sharepoint.com/_api/Web/GetFileByServerRelativePath(decodedurl='/DocLibrary/pdf_file.pdf')/$value", 
		type: 'get',  
		contentType: true, 
		processData: false,
		encoding: null,
		headers: { 
			accept: 'application/json',
			"Authorization": "Bearer " + code
			},
		beforeSend: function (request) {
			request.overrideMimeType('text/plain; charset=x-user-defined');
			},
		success: function(response){
			var binary = "";
			var responseTextLen = response.length;

			for ( i = 0; i < responseTextLen; i++ ) {
				binary += String.fromCharCode(response.charCodeAt(i) & 255)
			}

			var a = document.createElement('a');
			a.href = "data:application/pdf;base64," + btoa(binary);
			a.download = 'pdf_file.pdf';
			document.body.appendChild(a);
			a.click();
			a.remove();
		},
	});
}
</script>

Take a look at ‘beforeSend’, using this we are forcing the requested MIME type as ‘text/plain’, instead of the arraybuffer response.

Here is an alternate implementation of the ‘success’ method using JavaScript FileReader API.

success: function(response){                
                var i = 0,
                dataArray = new Uint8Array(response.length);
                for (; i < response.length; i++) {
                    dataArray[i] = response.charCodeAt(i)
                }

                var blob = new Blob([dataArray.buffer], {
                    type: "application/pdf"
                });
                let link = document.createElement('a');
                link.download = 'pdf_file.pdf';

                let reader = new FileReader();
                reader.readAsDataURL(blob); // converts the blob to base64 and calls onload

                reader.onload = function() {
                  link.href = reader.result;
                  link.click();
                };
            }

This code should work for any file types. We just have to change the file type (MIME type) properly.

Here is a list of Microsoft file types and MIME types:

File extensionFile typeMIME type
.docxMicrosoft Office Word 2007 documentapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.docmOffice Word 2007 macro-enabled documentapplication/vnd.ms-word.document.macroEnabled.12
.dotxOffice Word 2007 templateapplication/vnd.openxmlformats-officedocument.wordprocessingml.template
.dotmOffice Word 2007 macro-enabled document templateapplication/vnd.ms-word.template.macroEnabled.12
.xlsxMicrosoft Office Excel 2007 workbookapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xlsmOffice Excel 2007 macro-enabled workbookapplication/vnd.ms-excel.sheet.macroEnabled.12
.xltxOffice Excel 2007 templateapplication/vnd.openxmlformats-officedocument.spreadsheetml.template
.xltmOffice Excel 2007 macro-enabled workbook templateapplication/vnd.ms-excel.template.macroEnabled.12
.xlsbOffice Excel 2007 binary workbookapplication/vnd.ms-excel.sheet.binary.macroEnabled.12
.xlamOffice Excel 2007 add-inapplication/vnd.ms-excel.addin.macroEnabled.12
.pptxMicrosoft Office PowerPoint 2007 presentationapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.pptmOffice PowerPoint 2007 macro-enabled presentationapplication/vnd.ms-powerpoint.presentation.macroEnabled.12
.ppsxOffice PowerPoint 2007 slide showapplication/vnd.openxmlformats-officedocument.presentationml.slideshow
.ppsmOffice PowerPoint 2007 macro-enabled slide showapplication/vnd.ms-powerpoint.slideshow.macroEnabled.12
.potxOffice PowerPoint 2007 templateapplication/vnd.openxmlformats-officedocument.presentationml.template
.potmOffice PowerPoint 2007 macro-enabled presentation templateapplication/vnd.ms-powerpoint.template.macroEnabled.12
.ppamOffice PowerPoint 2007 add-inapplication/vnd.ms-powerpoint.addin.macroEnabled.12
.sldxOffice PowerPoint 2007 slideapplication/vnd.openxmlformats-officedocument.presentationml.slide
.sldmOffice PowerPoint 2007 macro-enabled slideapplication/vnd.ms-powerpoint.slide.macroEnabled.12
.oneMicrosoft Office OneNote 2007 sectionapplication/msonenote
.onetoc2Office OneNote 2007 TOCapplication/msonenote
.onetmpOffice OneNote 2007 temporary fileapplication/msonenote
.onepkgOffice OneNote 2007 packageapplication/msonenote
.thmx2007 Office system release themeapplication/vnd.ms-officetheme

You can also check the common MIME types list from Mozilla. https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types

Hope this will help someone in need.

An AJAX Class: To use AJAX (Asynchronous JavaScript and XML) in a better way


An AJAX Class: To use AJAX (Asynchronous JavaScript and XML) in a better way

Class: clsAjax.js

 

// JavaScript Document

/*

* This file creates the instance of xmlHttpRequest object, sends and

* receives the request and response respectively.

* @Author Udaybhanu Karmakar

*/

/*

* Static script to instantiate XMLHttp object for different browsers.

*/

 

function ServerXMLHTTPRequest()

{

          this.clientHttpHandler = create();

          this.httpMethod = “GET”;

          this.serverUrl = “”;

          this.isAsync = true;

          this.respFunc = “”;

          this.send = function () {

                                                if(this.serverUrl != “”)

                                                 {

                                                          this.clientHttpHandler.open(this.httpMethod, this.serverUrl, this.isAsync);

                                                          this.clientHttpHandler.onreadystatechange = this.respFunc;

                                                          this.clientHttpHandler.send(null);

 

                                                 }

                                      };

          this.receive = receive;       

}

 

 

/* This method creates the xmlHttpRequest object and returns it.

*/

function create()     

{

          var xmlHttpRequest = false;

 

          //Internet Explorer

          try{

                   xmlHttpRequest = new ActiveXObject(“Msxml2.XMLHTTP”);

                   //alert(“creating new Msxml2.XMLHTTP obj”);

          }catch (xml2Exception){

                   try{

                             xmlHttpRequest = new ActiveXObject(“Microsoft.XMLHTTP”);

                             //alert(“creating new Microsoft.XMLHTTP obj”);

                   }catch (xmlException){

                             xmlHttpRequest = false;

                   }

          }

 

          //Netscape, Mozila, Firefox, Safari, Opera

          if (!xmlHttpRequest && typeof XMLHTTPRequest == ‘undefined’){

                   try{

                             //alert(“creating new ff obj”);

                             xmlHttpRequest = new XMLHttpRequest();

                   }catch (genException){

                             XMLHttpRequest = false;

                   }

          }

         

          if (!xmlHttpRequest && window.createRequest){

                   try{

                             xmlHttpRequest = window.createRequest();

                   }catch (e){

                             xmlHttpRequest=false;

                   }

          }

 

          return xmlHttpRequest;

}

 

/*

* This method checks the state and the status of the response and

* depending on that fetches the response text.

* readystate: 0 – uninitialized, 1 – loading, 2 – loaded, 3 – interactive, 4 – complete

*/

function receive(){

          var status = null;

          try{

                   if (this.clientHttpHandler.readyState == 4){

                             status = this.clientHttpHandler.status;

                             if (status == 200){

                                      return true;

                             }

                   }

                   return false;

          }catch (genException){

                   alert(“Error accessing Data.\nStatus returned: ” + status);

          }

}

 

//Destructor

 

function destructObj(objToDestroy){

          objToDestroy = null; 

}

  

Suppose we have one text box and one button in a HTML page.

 

From this page users can add their emails in the mailing list by adding their email in the text box and clicking on the save button.

 

So in HTML first we have to create a page to display on text box and one button.

 

Page: addUserToMailingList.html

 

<html>

<head>

<title>Ajax Class Example – Mailing List</title>

</head>

<body>

<h1>Add my email to mailing list </h1>

<table width=”80%” border=”0″>

  <tr>

    <td width=”17%”>Email Address </td>

    <td width=”23%”><input name=”txtEmail” type=”text” id=”txtEmail”> </td>

    <td width=”60%”><input type=”button” name=”saveBtn” value=”Add email”></td>

  </tr>

</table>

</body>

</html>

 

Now in the onclick event for the Add email button we have to fire some code to save the email in the Mailing list in the background.

 

So after adding the JavaScript in the head section and adding the event listener for the Save button the HTML page now becomes:

 

<html>

<head>

<title>Ajax Class Example – Mailing List</title>

<script type=”text/javascript” src=””></script>

<script type=”text/javascript”>

var ajaxObject = null;

var response = null;

 

function saveEmail(){

          var emailAddr = document.getElementById(“txtEmail”).value;

          sendSaveEmailRequest(email);

}

 

/*

Function to send

*/

 

function sendSaveEmailRequest(email){

 

          //Initialize the Ajax Object

         

          if (ajaxObject == null){

                   ajaxObject = new ServerXMLHTTPRequest();

          }

                  

          //The url of the backend page to add the email address in Database

          serverURL = “save.user.emaillist.asp”;

          //Add the email address as query string

          //Add a random number at the end to stop IE caching

          queryString = “?userEmail=” + email + “&random=” + Math.random();

 

          if (queryString != “”){

                   serverURL += “?” + queryString;

          }

         

          if (serverURL != “”){

                             //Give the backgound page URL

                             ajaxObject.serverUrl = serverURL;

                             //Give the function name to execute after processing

                             ajaxObject.respFunc = receiveChangeData;

                             //Send asynchoronous request

                             ajaxObject.isAsync = true;

                             //Send the request

                             ajaxObject.send();

          }

}

 

function receiveChangeData(){

          if (ajaxObject.receive()){

                   //Destroy the response object for better use.

                   //There might be data of the previous call.

                  

                   if(response != null){

                             response = null;

                   }

 

                   //Now get the response as text

                   response = ajaxObject.clientHttpHandler.responseText;

                  

                   var str = “”;

                  

                   //If the backend page gives output as “OK” the user email successfully added

                  

                   if(response==’OK’){                     

                             alert(“User email added successfully in the email list”);             

                            

                   }else if(response==’NOK’){ //Else there is some problem adding

                             alert(“There is some problems adding user in the email list. \n Please check.”);

                   }

                   //Now destruct the object

                   destructObj(ajaxObject);

          }

}

</script>

</head>

<body>

<h1>Add my email to mailing list </h1>

<table width=”80%” border=”0″>

  <tr>

    <td width=”17%”>Email Address </td>

    <td width=”23%”><input name=”txtEmail” type=”text” id=”txtEmail”> </td>

    <td width=”60%”><input type=”button” name=”saveBtn” value=”Add email” onClick=”javascript:saveEmail()”></td>

  </tr>

</table>

</body>

</html>

 

 

Now we should create one backend page i.e save.user.emaillist.asp to save the data:

 

 

Page save.user.emaillist.asp

 

<%@LANGUAGE=”VBSCRIPT” CODEPAGE=”1252″%>

<%

Dim userEMail

 

userEMail = Request.QueryString(“userEmail “)

‘If email is not blank then add it to Database

 

If userEMail <> “” Then

‘Add user in Database

‘If addition success then

‘Response.write(“OK”)

‘Else

‘Response.write(“NOK”)

End If

%>