I'm trying to make simple file server. I have Node.js backend with MongoDB GridFS storage to store files. I'm getting files from server by gridfs-stream. On the front-end I`m using Angular. And I have two major problems:
When I'm using Blob to serve downloads, filename becomes: "d1c393df-b0d9-4ae5-befe-8d45b183eb54..." kind. I read a lot of docs about it and didn`t find any solutions.
When I`m serving downloads only by Express without authentication, files load correctly. But I send auth info via Angular and without them application will throw the error. I can specify route without authentication but this makes my application unsafe.
I hope you help me to:
Find another way to download files of any format.
Change my existing code to get things work correctly
My Angular Service to get files by constructing a Blob:
getFilesFactory.download = function(filename){
$http.get('/api/files/' + filename, {responseType:'arraybuffer'})
.then(function(data){
var stringCT = data.headers('Content-Type').toString();
console.log(stringCT);
var contentType = stringCT.substring(1, stringCT.length - 1);
console.log(contentType);
switch (contentType) {
case "image/jpeg":
file = new Blob([data.data], {type: 'image/jpeg'});
fileURL = URL.createObjectURL(file);
$window.open(fileURL);
break;
case "application/pdf":
file = new Blob([data.data], {type: 'application/pdf'});
fileURL = URL.createObjectURL(file);
$window.open(fileURL);
break;
case "application/msword":
file = new Blob([data.data], {type: 'application/msword'});
fileURL = URL.createObjectURL(file);
$window.open(fileURL);
break;
case "application/octet-stream":
file = new Blob([data.data], {type: 'application/octet-stream'});
fileURL = URL.createObjectURL(file);
$window.open(fileURL);
break;
default: console.log("no contentType match");
}
});
};
You don't need to use ajax for downloading file and opening it in using $window.open(fileURL);. You can just open new window with '/api/files/' + filename url and browser will start to download content. And you can control Content-Type and file name on a server side. You can take a look on example: Nodejs send file in response
Related
I have a django application deployed on AWS EBS. I have a function that takes a blob and create URL of it so that I can download the pdf file from the site. The function is working perfectly on localhost but in prod environment the created url from URL.createObjectURL() is redirecting to the error page or 404 page. Im using nginx as the reverse proxy. I have checked the blob is valid and the django function is generating the pdf layout correctly. Below is my js code to build the pdf download link
function showFile(blob){
var newBlob = new Blob([blob], {type: "application/pdf"})
if (!newBlob) {
console.error("Blob object is not valid");
return;
}
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
console.log(data)
var link = document.createElement('a');
link.href = data;
link.open="file.pdf";
link.download = 'Calculation.pdf';
link.click()
}
the console.log(data) is returning https://<mydomain>/d6527ea6-5c1d-457a-bfb2-2b6aff01ae31
Any idea on how I can make it work in my prod env?
Thank you
I tried to log the flow and everything is returning correctly. So I am not sure what is the issue
I am trying to read an avatar file uploaded via PostMan or any other client to my ExpressJS API.
So far, the recommendations I have being getting has all being Multer.
I don't want to use Multer as I am having some issues with it. I want to be able to read the file directly and upload it to a remote location of choice
Here is the code I have but not working
const getS3Params = (file) => {
let fileName = file.name;
let fileType = file.mimetype;
let fileContent = fs.readFileSync(file); /**Getting an error that says TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Object**/
return {
Bucket: process.env.S3_BUCKET_NAME,
Key: fileName,
ACL: 'public-read',
ContentType: fileType,
Body: fileContent
};
};
Is there a way to read the content of the file without using Multer?
Thanks.
I am currently trying to let the user of my website download a json object as a json-file.
With my following code i get the error message:
Error: Can't set headers after they are sent.
at SendStream.headersAlreadySent (\node_modules\send\index.js:390:13)
at SendStream.send (\node_modules\send\index.js:617:10)
at onstat (\node_modules\send\index.js:729:10)
at FSReqCallback.oncomplete (fs.js:168:5)
router.post('/about', ensureAuthenticated,
function (req, res, next) {
console.log(req.user);
var jsonVariable = JSON.stringify(req.user);
var path_tmp = create_tmp_file(jsonVariable);
res.download(path_tmp);
res.redirect('/about');
next();
}
);
Is there a better way to download a json object directly with no need to save it in the filesystem?
You can always inject some HTML into a page (or redirect to a page with some client-side JavaScript on it), and download it with the client. Just send the JSON string somehow to the new page you are redirecting to (it can even be a GET parameter), then download it with the following code (assuming the JSON string is in a variable called json):
var a = document.createElement("a")
a.href = URL.createObjectURL(
new Blob([json], {type:"application/json"})
)
a.download = "myFile.json"
a.click()
var jsonVariable = JSON.stringify(req.user);
var path_tmp = create_tmp_file(jsonVariable);
res.download(path_tmp);
Send the data with res.json and use content-disposition to make it a download.
res.set('Content-Disposition', 'attachment; filename=example.json')
res.json(req.user);
res.redirect('/about');
next();
And don't do that (which is the cause of the error). You are responding with a download. You can't say "Here is the file you asked for" while, at the same time say, "The file you asked for isn't here, go to this URL instead".
Unable to request service with blob content-type by REST API (GET), the file goes corrupted, below is a snippet that I used to get get the file.
PDF File is retrive from docware
while checking the downloaded pdf file size is less than the original file from the server and it was corrected.
handleDownload(url,fileName){
var element = document.createElement("a");
var file = new Blob([url], { type: "application/pdf", });
element.href = URL.createObjectURL(file);
element.download = fileName;
element.click();
}
I'm downloading a multi-part mime encoded image to iOS like this:
var ft = new FileTransfer();
url = encodeURI(url);
ft.download(url, path, function(fileEntry) {}, function(err) {});
with
path = "file://localhost/var/mobile/Applications/D702F059-A29F-4FF4-A165-D4A903DEDE7D/Documents/captured/2419747919.jpeg"
and get the following error:
body: "Could not create path to save downloaded file: The operation couldn’t be completed. (Cocoa error 513.)"
code: 1 (file not found)
http status: 200
This hints to an invalid path, but I can't see anything wrong with it. I get the path like this:
path = fs.root.toURL();
Everything else works fine and files can be stored in exactly the same path by taking photos. Just not via a FileTransfer download.
Any ideas or a bug in Phonegap 3.0? Thanks!
UPDATE - Workaround
FileWriter works and now even saves blobs on iOS and Android. Example code:
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
var blob = new Blob([xhr.response], {type: 'image/jpeg'});
// save via FileWriter
};
xhr.send();
I found the problem in iOS:
The path:
path = "file://localhost/var/mobile/Applications/D702F059-A29F-4FF4-A165-D4A903DEDE7D/Documents/captured/2419747919.jpeg"
does not work because it is an URL with "localhost" in it.
From FileEntry in Cordova one can get a string using "fullPath" and "toURL" ... on Android they work both to write a file.
On iOS only the fullPath works ... the URL does not successfully write a file!
I had problems with that while working on the iOS Simulator, but once I tested it on the actual device, it worked.
use nativeURL to get the prefix and append your file name to it and pass it to FileTransfer object it will work.
You'll want to use FileEntry.toURL() to get a path that looks like this:
cdvfile://localhost/persistent/path/to/file
See the documentation here: https://github.com/apache/cordova-plugin-file-transfer