Display PDF file stored in S3 bucket - node.js

Im using multer-s3 to upload a PDF to S3 bucket, and it works, but now I need to display the PDF without downloading it (just like this) and I already tryied to use iframe, embed and object, each one with the src='link_to_s3_file' and when I access the page it just download the file.
That's my code to configure the upload:
const multer = require('multer')
const multerS3 = require('multer-s3')
const AWS = require('aws-sdk')
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION
})
const s3 = new AWS.S3()
const upload = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_S3_BUCKET,
acl: 'private',
contentDisposition: 'attachment',
contentType: multerS3.AUTO_CONTENT_TYPE,
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function (req, file, cb) {
cb(null, file.originalname)
}
})
})
How can I display the PDF instead of download it?

In order to open PDF directly, without downloading it, you should change 2 things:
ContentDisposition='inline'
ContentType='application/pdf'
If you're sure that multerS3.AUTO_CONTENT_TYPE will recognize it correctly, you might not have to change this, but ContentDisposition is for sure one thing you have to change. attachment means that it will download it and inline is to open it in browser directly.

Related

Not getting the success response after video upload on s3 node.js

I am using the node.js as a backend and needs to upload the video on Amazon S3.
For that I am using the multer module but I need to know the efficient and standard way for uploading the video.
Generally we see that when we upload anything on the any good platfrom then there is a proper mechanism for uploading the video like:
When video is on uploading state, user get the response that how much percent is left for uploading the video
After uploading the video user get the response that video is uploaded successfully.
There is a handler which allow specific type of format to allow video.
There is a few limit size also which warn the user that maximum size is 20mb or 50 mb.
I am bit struggling about the good tutorial but unable to find as everywhere is sharing the tutorials about the image upload. So I thought I will raise the question which will help many others also regarding the same
I have implemented the process by which video will be uploaded on S3 but not getting the response after upload. It directly return the response and video will be uploaded in background.
I am sharing my implementation:
customapi.js file
const express = require('express');
const router = express.Router();
const helper = require('./file-upload');
const videoHandler = require('./videohandler');
// Post the video
router.post(
'/uploadvideo',
helper.single('media'),
videoHandler .uploadVideo
);
file-upload.js file
const AWS = require('aws-sdk')
const multer = require('multer')
const multerS3 = require('multer-s3')
const uuid = require('uuid/v1');
AWS.config.update({
accessKeyId: process.env.keyId,
secretAccessKey: process.env.accessKey,
});
const s3 = new AWS.S3();
const upload = multer({
storage: multerS3({
s3:s3,
bucket: process.env.bucketname,
acl: 'public-read',
contentType: multerS3.AUTO_CONTENT_TYPE,
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname})
},
key: function (req, file, cb) {
console.log(file) // This will print the filename which we can search in s3.
cb(null, uuid()+file.originalname)
console.log(uuid() + file.originalname)
}
})
})
videohandler.js file
module.exports = {
uploadVid: async (req, res) => {
try {
return res.send({message: "Done"})
} catch (error) {
console.log(error);
return res.send({message: "Error"})
}
}
}
I know what is happening exactly by which I am getting the response instantly instead of after the file upload.
When api calls -> helper.single('media') will invoke and process to start performing the task -> meanwhile videoHandler.uploadVideo will also called which directly send the response as there is no callback which understand the uploading process and return response accordingly.
Please share the best and efficient way as it supports many people also who is struggling for uploading the video.
Any help or suggestion is really appreciated.
Update Question
Many people sharing the way that video first upload on local disk and then it upload on S3. I need to know that is it a good behaviour. I mean for performing the task we need to do the double work instead of directly upload. It will consume the bandwidth and storage of the application on server.
I could handle it in this way. check whether is it applicable to your scenario.
App.js
router.post("/upload_service",
(req, res, next) => {
const upload = UploadController.upload.single('file')
upload(req, res, (err) => {
if (err) {
const error = new Error('Image upload error');
return next(error);
}
return next()
})
},
SomeController.createMethod)
UploadController.js
const multer = require('multer')
const multerS3 = require('multer-s3')
const AWS = require('aws-sdk')
const upload = multer({
storage: multerS3({
s3: new AWS.S3(),
bucket: 'bucket_name',
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function (req, file, cb) {
const file_name_timestamp = Date.now().toString()
cb(null, `path/${file_name_timestamp}.${String(file.mimetype).split('/').pop()}`);
},
ContentType: "application/octet-stream",
})
})
module.exports = {
upload
}
SomeController.js
const createMethod = async function (req, res) {
if (!req.file) {
res.send('File missing')
}
}
Once file upload middleware was success, SomeController.createMethod will be triggered. using req.file, creation data can be visible.

Upload multiple images on Amazon S3 using Node.js

I am trying to upload images to amazon s3. However req.files is still undefined. I don't understand where is my code going wrong. The images are sent from Angular frontend. 'artFileLocations' is array of files in FormData. How do I fix this?
const router = require('express').Router()
const AWS = require('aws-sdk')
const multer = require('multer');
const multerS3 = require('multer-s3');
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
var s3 = new AWS.S3();
// Unique name of aws s3 bucket created
const myBucket = 'nish.images';
// Multer upload (Use multer-s3 to save directly to AWS instead of locally)
var upload = multer({
storage: multerS3({
s3: s3,
bucket: myBucket,
// Set public read permissions
acl: 'public-read',
// Set key/ filename as original uploaded name
key: function (req, file, cb) {
cb(null, file.originalname)
}
})
})
router.post('/', upload.array('artFileLocations', 3), function(req, res) {
console.log('Reaching addPainting')
console.log(req.body, req.files)
});
module.exports = router;
Your code looks fine.
but can you update your HTML file like this:
<input type="file" name="artFileLocations" multiple>
If you already update your HTML file, then I think you don't face any other error.
Try uploading single file and check whether your req.files is working or not. I also encountered this error where the multiple file upload was not working. So, check if the req.files is working for single file upload.

AWS file load works on localhost, but doesn't work on EC2 (node, express, react). Get 403 Forbidden

I have application on Node. API endpoint for sending files to AWS contains this part
const multer = require('multer');
const aws = require('aws-sdk');
const multerS3 = require('multer-s3');
aws.config.update({
secretAccessKey: require("../config/keys").aws.key,
accessKeyId: require("../config/keys").aws.id,
region: 'eu-central-1'
});
const s3 = new aws.S3();
const storage = multerS3({
s3: s3,
bucket: require("../config/keys").aws.bucket,
key: function (req, file, cb) {
cb(null, Date.now().toString());
}
});
const upload = multer({ storage: storage });
module.exports = upload;
I call it in route this way
const upload = require('../../middleware/multer-aws');
router.post("/add", upload.any('file'), (req, res) => {
...
When I test loading files on localhost it works well, but when I do the same on EC2 instance I have 403 Forbidden response.
In my code I don't have 403 codes, so it definetely comes from AWS.
I can't get where is the problem and how to solve it. Any ideas?
Looks like some NACL issue outbound HTTP access might be blocked from the EC2 instance, if AWS access keys and secret keys are perfectly working in local instance and uploading files to S3, it should have worked from EC2, please check NACL
Issue solved. I checked pm2 logs, found message about InvalidAccessKeyId. Checked env variable and found, that I messed key and id on prod.

saved image can't open saved image on node server

I post formdata which includs image file to node server.
This is server request code.
const multer = require('multer')
const avatar = multer({dest: 'public/avatar/'})
app.post('/uploadPhoto', avatar.single('file'), function(req, res) {
console.log(req.file)
})
This is console result.
file: {
fieldname: 'file',
originalname: 'git - Copy.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: 'public/avatar/',
filename: 'ac578f8b2b1a629c89f85d3a7215ed18',
path: 'public\\avatar\\ac578f8b2b1a629c89f85d3a7215ed18',
size: 4786565
}
And I can see public/avatar/ac578f8b2b1a629c89f85d3a7215ed18 on my computer.
But I can't open it.
How to convert request file data to correct image type data.
Now if I try to open it, I can get this sentence.
The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.
We need to specify the extension of the file we are trying to save. You can use the diskstorage engine to have more control over how files are stored in the disk.
const storage = multer.diskStorage({
destination: function(req,file,callback){
const path = `/public/avatar/`;
callback(null, path);
},
filename: function(req,file,callback){
callback(null,`${file.originalname}`);
}});
In the file object, we have all the properties of file like originalname and we can use this to set filename.
Finally, pass this in multer
const upload = multer({storage: storage});

How to access files on digital ocean spaces with multer

I have managed to upload pdf files on digital ocean spaces with a node js app as shown below.
I don't know how to then access those files and display them to the user. I got the code below from this tutorial, object storage file upload, but there isn't an example on how to then access the files.
When I just try to access them with their url, I just get white space.
I have made them public but still get absolutely nothing trying to access them from the url.
Is there a way to access the files using multer still, do I have to make a get request with the RESTFul API? How do I access files stored in a digital ocean spaces?
This is how I upload files
const aws = require("aws-sdk");
const multer = require("multer");
const multerS3 = require("multer-s3");
const spaceEndPoint = new aws.Endpoint("ams3.digitaloceanspaces.com");
const s3 = new aws.S3({
endpoint:spaceEndPoint
})
const upload = multer({
storage:multerS3({
s3:s3,
bucket: "fileRepo",
acl:"public-read",
key:function(request, file, cb){
console.log(file);
cb(null, file.originalname);
}
})
}).array("upload",1);
router.get("uploadFile", function(req,res){
upload(req, res, function(error){
if(error){
console.log(error);
return res.redirect("/");
}
});
})
And this is how I try to retrive the pdfs
router.get("/contentPage", function(req, res){
var fileName = req.body.department;
var directory = "https://fileRepo.ams3.digitaloceanspaces.com/" + fileName + ".pdf";
res.render("fileview", {dir: directory});
})
<div id="departmentListWrapper" class="container">
<embed src="<%= dir %>" width="800px" height="2100px" />
</div>
Can anyone tell me what the issue might be with retrieving these files?
Try this code snippet, works fine for me
import multer from 'multer';
import multerS3 from 'multer-s3';
aws.config.update({
accessKeyId: 'your access key',
secretAccessKey: 'your secret key'
});
var filepath = "path of files folder"
// Create an S3 client setting the Endpoint to DigitalOcean Spaces
var spacesEndpoint = new aws.Endpoint('nyc3.digitaloceanspaces.com');
var s3 = new aws.S3({endpoint: spacesEndpoint});
var params = {
Bucket: bucketName,
Key: keyName,
Body: fs.createReadStream(filepath),
ACL: 'public-read'
};
s3.putObject(params, async function(err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
It turns out that digital ocean did not know what type of file was being uploaded, I had to make it so that the file type is read before it is uploaded so that the browser knew what type of file I was trying to upload by adding the line
contentType: multerS3.AUTO_CONTENT_TYPE
to the multer object so that it looks like this.
const upload = multer({
storage:multerS3({
s3:s3,
bucket: "fileRepo",
contentType: multerS3.AUTO_CONTENT_TYPE
acl:"public-read",
key:function(request, file, cb){
console.log(file);
cb(null, file.originalname);
}
})
}).array("upload",1);

Resources