I am working on MERN application and I am facing issue in displaying the image.Using multer, the image path store in the MongoDB after file uploaded successfully and the image also stores in the folder "uploads", but there is problem I am getting while retrieving the image path from db.
all the text data retrieved but displaying image give me error.
Error I got:
CANNOT GET http://localhost:3000/uploads/image-1614468761737.jpg
Here is the code.
const express = require("express")
const path = require("path")
const route = express.Router()
const Post = require("../models/postModel")
const multer = require("multer")
const storage = multer.diskStorage({
destination(req,file,cb){
cb(null,"uploads/")
},
filename(req,file,cb){
cb(null, `${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`)
}
})
const upload = multer({
storage,
filefilter: function(req,file,cb) {
const filetypes = /jpg|jpeg|png/
const extname = filetypes.test(path.extname(file.originalname).toLowerCase())
const mimetype = filetypes.test(file.mimetype)
if(extname && mimetype){
return cb(null, true)
}else{
cb(null,false)
}
},
})
route.post("/upload",upload.single("image"),(req,res)=>{
const file = req.file.path.replace(/\\/g,"/" )
res.send(`/${file}`)
})
route.post("/", async(req,res)=>{
const post = req.body
try {
const createpost = new Post(post)
await createpost.save()
res.status(200).json(createpost)
} catch (error) {
res.status(404).json({msg:"create post failed"})
}
})
module.exports = route
in the main file I also add
app.use("/uploads",express.static(path.join(__dirname,"/uploads")))
file structure:
file structure and uploads folder is in the root
GitHub:
https://github.com/mozi47/Check-error
Related
Please I'm new to Nodejs and I'm trying to create an image uploader that will upload files to my server using Nodejs and multer, but the problem is in getting the image back to be displayed in my angular app.
This is the backend code:
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const app = express();
var corsOptions = {
origin: "*",
optionsSuccessStatus: 200,
}
app.use(cors(corsOptions));
app.use(express.static('uploads'));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads");
},
filename: function (req, file, cb) {
cb(null, `${Date.now()}_${file.originalname}`);
},
})
const upload = multer({ storage });
app.post('/file', upload.single('file'), (req, res) => {
const file = req.file;
if (file) {
res.json(file);
} else {
throw new Error('File upload unsuccessful')
}
})
const port = 3000;
app.listen(port, () => console.log(`Server running on port ${3000}`));
This is my app.html code:
<input type="file" name="image" (change)="upload($event)">
This is my app.ts code:
upload(event: any) {
const file = event.target.files[0];
const formdata = new FormData();
formdata.append('file', file)
this.httpClient.post('http://localhost:3000/file', formdata)
.subscribe((data) => {
console.log(data);
},
(error) => {
console.log(error)
})
Please help me retrieve the image so that I can use it in my angular app. Thank you.
There are two ways you can achieve this. Both the approaches have their own pros and cons.
Store the image locally and send the URL back to the browser.
if (req.files) {
const fileNames = [];
for (let i = 0; i < req.files.length; i++) {
const file = req.files[i];
const relPath = "your/img/path";
const dirName = path.join(BASE_APP_PATH, relPath);
const relFileName = path.join(
relPath,
`${i + 1}_${file.originalname.replace(",", "")}`
);
const img_location = `${dirName}/${
i + 1
}_${file.originalname}`;
if (!fs.existsSync(dirName)) fs.mkdirSync(dirName, { recursive: true });
fs.writeFileSync(img_location, file.buffer, {});
fileNames.push(relFileName);
}
}
Get the image and send back base64 to the browser.
const encoded = req.files[0].buffer.toString('base64')
Multer receives the Form Data, but leaves all fields, including the image files, in the req.body object. Here is my code:
React:
const state = {
// other fields
images: [], // array of image files
};
let formData = new FormData();
// append other fields
formData.append("images", state.images);
await fetch(url, {
body: formData,
// config
});
Express:
const express = require("express");
const router = express.Router();
const controller = require("./controller");
const multer = require("multer");
const storage = multer.memoryStorage();
const imageFilter = (req, file, cb) => {
// accept image files only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/i)) {
return cb(new Error("Only image files are allowed!"), false);
}
cb(null, true);
};
const upload = multer({ storage, fileFilter: imageFilter });
// other routes
router.post("/", upload.array("images"), controller.handleImagePost);
Multer doesn't parse the Form Data files if they are nested in an array. It's best to loop over your React state array, and append each file individually to the formData object. (See FormData API and Multer docs)
for (const image of state.images) {
formData.append("image", image, image.path);
}
Make sure to match the form data field name in your multer middleware code
router.post("/", upload.array("image"), controller.handleImagePost);
I am trying to upload multiple files to Google Cloud bucket using Node.js and multer. It works with multer.single function but I don't know how to upload multiple images at once.
const bucket = gc.bucket('still-cover');
// Multer is required to process file uploads and make them available via
// req.files.
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
Router.post('/test/upload',multer.array('files',5),async(req,res)=>{
if (!req.files) {
res.status(400).send('No file uploaded.');
return;
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.files.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('finish', res => {});
blobStream.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`
res.status(200).send(publicUrl);
});
blobStream.end(req.files.buffer);
});
You can use multer.array('files', numberoffiles) or multer.any()to upload files to your Google Cloud Storage Bucket. You can use the following code to upload multiple files using Multer:
const express = require('express');
const path = require('path');
const cors = require('cors');
const Multer = require('multer');
const bodyParser = require('body-parser');
const {Storage} = require('#google-cloud/storage');
// Creates a client
const storage = new Storage();
const bucket = storage.bucket('YOUR_BUCKET_NAME')
const PATH = './public/';
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
app.get('/', function(req, res){
res.json({
json: "json"
});
})
// You can also use multer.array('data', numberofFiles)
app.post('/', multer.any(), function(req, res) {
console.log(req.files);
var counter = 0;
if (!req.files) {
res.status(400).send('No file uploaded.');
return;
}
// Create a new blob in the bucket and upload the file data.
req.files.forEach((fil) => {
const blob = bucket.file(fil.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('finish', () => {
counter+=1
// The public URL can be used to directly access the file via HTTP.
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`
if(counter>=2){
res.status(200).send(publicUrl);
}
});
blobStream.end(req.files.buffer);
});
});
app.listen(3000, function () {
console.log("Working on port 3000");
});
On the line blobStream.end(req.files.buffer); replace files.buffer with fil.buffer.
I am trying to upload a PDF document on Cloudinary through a node.js server.
The current approach I am using is inadequate and doesn't work.
I will appreciate if anyone can proffer a solution to this problem that works, thank you.
Cloudinary Storage Configuration:
const cloudinary = require("cloudinary").v2,
{ CloudinaryStorage } = require("multer-storage-cloudinary");
cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
const storage = new CloudinaryStorage({
cloudinary: cloudinary,
folder: "<some_folder>",
allowedFormats: ["jpg", "png", "pdf"],
});
module.exports.store = storage;
Image Upload Route:
const express = require("express"),
router = express.Router(),
cors = require("cors"),
fileUploadController = require("../../../controllers/haulage/users/fileUploadController");
const authenticate = require("../../../auth/auth"),
multer = require("multer"),
storage = require("../../../../config/cloudinary").store,
parser = multer({ storage: storage });
router
.route("/images")
.put(
authenticate,
cors(),
parser.array("image"),
fileUploadController.uploadImage
);
module.exports = router;
Image Upload Controller:
exports.uploadImage = async (req, res) => {
try {
const events = JSON.parse(JSON.stringify(req.files));
const urls = [];
events.map((e) => {
const url = e.path;
urls.push(url);
});
res.status(201).json({ URLS: urls });
} catch {
res.status(500).json({ error: "Server Error, Image Failed to Add" });
}
};
Are you part of the free plan in Cloudinary? If yes, it might be related to this issue: https://support.cloudinary.com/hc/en-us/articles/360016480179-Why-does-my-pdf-link-isn-t-working-
If not, can you please elaborate on the issue? where do you see the error?
The code to upload pdf ( same as any image):
var cloudinary = require('cloudinary')
cloudinary.v2.uploader.upload("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",function(res,err){console.log(res,err)});
I am trying to upload images to s3 Bucket. And have tried many solutions online yet I get the above errors. I don't want to store images locally, instead I want to upload them directly to s3 bucket. Any help would be appreciated.
This is Upload.js file
const AWS = require('aws-sdk');
const Keys = require('../Config/dev');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios').default;
const multer = require('multer');
const multerS3 = require('multer-s3');
const s3 = new AWS.S3({
accessKeyId: Keys.accessKeyId,
secretAccessKey: Keys.secretAccessKey,
region : 'ap-south-1'
});
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'thebucketname',
acl : "public-read",
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file , cb){
cb(new Date().toISOString().replace(/[-T:\.Z]/g, "") + file.originalname);
}
})
});
module.exports = upload;
This is the router code
const express = require('express');
const Router = express.Router();
const controllers = require('../controllers/controllers.js');
const uploader = require('../controllers/Upload');
const singleUpload = uploader.single('img');
Router.post('/single-image',(req, res)=>{
singleUpload(req, res , (err)=>{
if(!req.file){
console.log(req.file);
}else
{
console.log(req.file);
return res.json({'imageUrl': req.file.location});
}
});
});
This is how I am using postman for api request. I have also set Content-Type to Multipart/form-data inside the Headers in postman. I get the error "undefined" for req.file when I do this.
Also, If I use
app.use(multer({dest:'./public/uploads/'}).single('file'));
my file gets stored in the 'uploads' folder but then I get the error "req.file.location undefined", and file doesn't upload to aws.
Firstly, if you want to upload files to s3 and not store it on your server, you can store the uploaded file as an in-memory buffer instead of writing it on your server and then uploading to s3. NOTE: this in-memory method is not recommended with large files or a large number of small files, because you need to ensure that your server has enough memory to deal with the uploads.
Then you can just pass the buffer to the s3 upload function. I don't know much about some package called multer-s3 that you've apparantly used so I'm not using that. I had made it for an array of files but it should work for single files also. I combined your code with some of my code and came up with the following:
//aws-sdk for node
const AWS = require('aws-sdk');
AWS.config.update({ region: <your region here> });
//S3
const S3 = new AWS.S3({});
const express = require('express');
const Router = express.Router();
const controllers = require('../controllers/controllers.js');
const uploader = require('../controllers/Upload');
//import multer
const multer = require("multer");
//make multer ready for in-memory storage of uploaded file
const multerMemoryStorage = multer.memoryStorage();
const multerUploadInMemory = multer({
storage: multerMemoryStorage
});
//using multer.single as a middleware is what I prefer
Router.post('/single-image',multerUploadInMemory.single("filename"),async(req, res)=>{
try{
if(!req.file || !req.file.buffer){
throw new Error("File or buffer not found");
}
const uploadResult = await S3.upload({
Bucket: "yourBucketName",
Key: "WhateverKeynameYouWantToGive",
Body: req.file.buffer,
ACL: 'public-read'
}).promise();
console.log(`Upload Successful!`);
res.send({
message: "file uploaded"
})
}catch(e){
console.error(`ERROR: ${e.message}`);
res.status(500).send({
message: e.message
})
}
});
You can first use console.log(req.file) to see if it's not undefined (which it shouldn't be) and you can check if you're getting the buffer property in the file.
Also, it says in a "warning" here that you should never add multer as a global middleware, so app.use(multer({dest:'./public/uploads/'}) is a no-no.