Download fileResult docx on client side - javascript

I am working on a client-server application, and at the moment i am returning a file result in my web api controller, like this:
FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes(docDestination), "application/msword")
{
FileDownloadName = "myFile.docx"
};
return result;
on my client side i receive the response like this:
i thaught at begin that the browser detects the file automaticly and fires the download dialog, but no, so i tried to treat the result as a blob like this:
.then(response => {
console.log("here lives the response:", response);
var headers = response.headers;
var blob = new Blob([response.bodyText], { type: headers['application/msword'] });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "Filename";
link.click();
the download fires, but the content is not identified as docx file, and his content is broken.
Any tip on how to do it?
Thanks

Related

Create XLSX file from file contents from server and save it

I got Node JS server which gets XLSX file contents from metabase:
app.get('/channels', async (req, res) => {
// make request to metabase and take response as XLSX
const queryRequestURL = `${api}/public/card/${cardId}/query/xlsx?parameters=${params}`;
const result = got(queryRequestURL);
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader("Content-Disposition", "attachment; filename=file.xlsx");
return res.send(res);
});
It returns file contents like
So when i make request to server and receive response - it comes as file contents above.
I need to download this data as ordinary excel file on browser side.
What i've tried:
// make request with typical fetch and get result to res variable.
const filename = 'file.xlsx';
const file = new File(res, filename ,{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
// create link and click it virtually to download created file
var a = document.createElement('a');
a.href = window.URL.createObjectURL(file);
a.download = filename;
a.click();
But I'm getting the error:
Uncaught (in promise) TypeError: Failed to construct 'Blob': The provided value cannot be converted to a sequence.
I think that I'm doing something wrong and there is more simple way to download file.
Without seeing how you're fetching, it's hard to know. But you should be able to use response.blob() to download the result.
fetch("${api}/channels}", {
method: "GET",
})
.then((response) => response.blob())
.then((blob) => {
var url = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = url;
a.download = "file.xlsx";
document.body.appendChild(a);
a.click();
a.remove();
});
As Joey Ciechanowicz mentioned, we should return response.buffer() from backend and work with its data as blob at frontend.
I mean
NodeJS side (using Got):
const result = got(queryRequestURL, {
headers: headers
});
return await result.buffer()
Frontend side (pure JavaScript):
// fetch data
const result = await fetch(api + path);
return result.blob();
// download file
const filename = 'export.xlsx';
var url = window.URL.createObjectURL(result);
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
a.remove();

How to read filename from response - reactJs

I'm downloading a file from a server. There I'm setting a file name which I would like to read on a frontend. Here is how I'm doing it on server:
string fileName = "SomeText" + DateTime.UtcNow.ToString() + ".csv";
return File(stream, "text/csv", fileName);
Basically I will return different types of files, sometimes csv sometimes xlsxand sometimes pdf. So I want to get filename on a frontend so I might save it as it should be for example SomeText.pdf it will be saved automatically on local machine as pdf.
Here is my frontend code:
getFileFromServer(params).then(response => {
console.log('server response download:', response);
const type = response.headers['content-type'];
const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' });
//const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'file.xlsx'; // Here I want to get rid of hardcoded value instead I want filename from server
link.click();
link.remove(); // Probably needed to remove html element after downloading?
});
I saw in Network tab under Response Headers that there is a Content-Disposition which holds that info:
Content-Disposition: attachment; filename="SomeText22/08/2019 10:42:04.csv";
But I don't know is it available in my response and how can I read it in my frontend part so I might replace
link.download = 'file.xlsx';
with Path from a server ..
Thanks a lot guys
Cheers
this is a special type of header so to get this header in frontend the backend person should allow from his end. then you can the headers in the response
response.headers.get("content-disposition")
the below code I have used in my project
downloadReport(url, data) {
fetch("url of api")
.then(async response => {
const filename = response.headers
.get("content-disposition")
.split('"')[1];
const text = await response.text();
return { filename, text };
})
.then(responseText => this.download(responseText))
.catch(error => {
messageNotification("error", error.message);
throw new Error(error.message);
});
}
You can get filename from Content-Disposition header by this way
getFileFromServer(params).then(response => {
// your old code
const [, filename] = response.headers['content-disposition'].split('filename=');
const link = document.createElement('a');
link.download = filename;
// your old code
});
Hope this will help
To get the filename from Content-Disposition on client side(frontend) you must give permission from server side(Backend). Spring users can use
#CrossOrigin(value = {"*"}, exposedHeaders = {"Content-Disposition"})
#Controller
#RequestMapping("some endpoint")
in their controller class.
Then from frontend we can get filename using.
const filename = response.headers['content-disposition'].split('filename=')[1];
Hope this helps. Above solution worked fine for me

How to create download feature using ASP.NET Core 2.1 and React JS?

I'm using ASP.NET Core and React JS. I'm newbie to this both platforms. I have used Axios for requesting data and getting response from server. But I have not requested images or any kind of file from server. This time I'm working on Download feature where user will click on button and can download desired file which is of .png, .jpg, .pdf format. I'm not understanding how can server will send data? I read, I needed to send base64 data which is converted from blob format. But not understanding how to request data from client and how server will serve desired file. In DB, I have stored only address of file e.g. /images/img1.jpg. This file actually resides in wwwroot/images folder. I have used downloadjs for downloading which is working correctly but after downloading, that image is not readable as it does not have any content.
Please anyone help me to implement this feature.
First you need API to download data something like this
public async Task<IActionResult> Download(string filename)
{
if (filename == null)
return Content("filename not present");
var path = Path.Combine(
Directory.GetCurrentDirectory(),
"wwwroot", filename);
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, GetContentType(path), Path.GetFileName(path));
}
private string GetContentType(string path)
{
var types = GetMimeTypes();
var ext = Path.GetExtension(path).ToLowerInvariant();
return types[ext];
}
private Dictionary<string, string> GetMimeTypes()
{
return new Dictionary<string, string>
{
{".txt", "text/plain"},
{".pdf", "application/pdf"},
{".doc", "application/vnd.ms-word"},
{".docx", "application/vnd.ms-word"},
{".xls", "application/vnd.ms-excel"},
{".xlsx", "application/vnd.openxmlformats
officedocument.spreadsheetml.sheet"},
{".png", "image/png"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".gif", "image/gif"},
{".csv", "text/csv"}
};
}
Then download file like this
axios({
url: 'your url',
method: 'POST', // Worked using POST or PUT. Prefer POST
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
Ref link

I'm trying to download a pdf file from a node server to a react client but when I open it, it shows blank

I'm just reading the data from the file from node and sending the content type as "application/pdf".
My node version is 10.
serverside.js:
var file = path.join(__dirname,'Rajesh.pdf');
fs.readFile(file, function(err, data){
res.contentType("application/pdf");
res.send(data)
})
clientside.js:
axios.get('/api/downloadcv')
.then(res => {
const url = window.URL.createObjectURL(new Blob([res.data]
,{type: "application/pdf"}))
var link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'resume.pdf');
document.body.appendChild(link);
link.click();
})
The pdf is getting downloaded but it shows nothing, when I opened it with Vs Code it showed me something like this:
%PDF-1.4
%äüöß
2 0 obj
<</Length 3 0 R/Filter/FlateDecode>>
stream
x��\K�d�m������n�u�F���Ad�d
Just add responseType as header with value arraybuffer. You should be good to go.
axios.get('/api/downloadcv', {responseType: 'arraybuffer'})
Hope that helps!!!

PDF is blank when downloading using javascript

I have a web service that returns PDF file content in its response. I want to download this as a pdf file when user clicks the link. The javascript code that I have written in UI is as follows:
$http.get('http://MyPdfFileAPIstreamURl').then(function(response){
var blob=new File([response],'myBill.pdf',{type: "text/pdf"});
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myBill.pdf";
link.click();
});
'response' contains the PDF byte array from servlet outputstream of 'MyPdfFileAPIstreamURl'. And also the stream is not encrypted.
So when I click the link, a PDF file gets downloaded successfully of size around 200KB. But when I open this file, it opens up with blank pages. The starting content of the downloaded pdf file is in the image.
I can't understand what is wrong here. Help !
This is the downloaded pdf file starting contents:
solved it via XMLHttpRequest and xhr.responseType = 'arraybuffer';
code:
var xhr = new XMLHttpRequest();
xhr.open('GET', './api/exportdoc/report_'+id, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
if (this.status == 200) {
var blob=new Blob([this.response], {type:"application/pdf"});
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="Report_"+new Date()+".pdf";
link.click();
}
};
xhr.send();
i fetched the data from server as string(which is base64 encoded to string) and then on client side i decoded it to base64 and then to array buffer.
Sample code
function solution1(base64Data) {
var arrBuffer = base64ToArrayBuffer(base64Data);
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([arrBuffer], { type: "application/pdf" });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
var data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
document.body.appendChild(link); //required in FF, optional for Chrome
link.href = data;
link.download = "file.pdf";
link.click();
window.URL.revokeObjectURL(data);
link.remove();
}
function base64ToArrayBuffer(data) {
var binaryString = window.atob(data);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes;
};
I was facing the same problem in my React project.
On the API I was using res.download() of express to attach the PDF file in the response. By doing that, I was receiving a string based file. That was the real reason why the file was opening blank or corrupted.
In my case the solution was to force the responseType to 'blob'. Since I was making the request via axios, I just simply added this attr in the option object:
axios.get('your_api_url_here', { responseType: 'blob' })
After, to make the download happen, you can do something like this in your 'fetchFile' method:
const response = await youtServiceHere.fetchFile(id)
const pdfBlob = new Blob([response.data], { type: "application/pdf" })
const blobUrl = window.URL.createObjectURL(pdfBlob)
const link = document.createElement('a')
link.href = blobUrl
link.setAttribute('download', customNameIfYouWantHere)
link.click();
link.remove();
URL.revokeObjectURL(blobUrl);
solved it thanks to rom5jp but adding the sample code for golang and nextjs
in golang using with gingonic context
c.Header("Content-Description", "File-Transfer")
c.Header("Content-Transfer-Encoding", "binary")
c.Header("Content-Disposition","attachment; filename="+fileName)
c.Header("Content-Type", "application/pdf; charset=utf-8")
c.File(targetPath)
//c.FileAttachment(targetPath,fileName)
os.RemoveAll(targetPath)
in next js
const convertToPDF = (res) => {
const uuid = generateUUID();
var a = document.createElement('a');
var url = window.URL.createObjectURL(new Blob([res],{type: "application/pdf"}));
a.href = url;
a.download = 'report.pdf';
a.click();
window.URL.revokeObjectURL(url);
}
const convertFile = async() => {
axios.post('http://localhost:80/fileconverter/upload', {
"token_id" : cookies.access_token,
"request_type" : 1,
"url" : url
},{
responseType: 'blob'
}).then((res)=>{
convertToPDF(res.data)
}, (err) => {
console.log(err)
})
}
I was able to get this working with fetch using response.blob()
fetch(url)
.then((response) => response.blob())
.then((response) => {
const blob = new Blob([response], {type: 'application/pdf'});
const link = document.createElement('a');
link.download = 'some.pdf';
link.href = URL.createObjectURL(blob);
link.click();
});
Changing the request from POST to GET fixed it for me

Categories

Resources