File upload with multer returning undefined - javascript

I'm currently trying to implement file-uploads for my application, in which I use ReactJS, node.js with express, and MongoDB and mongoose. I'm using multer middleware for fileuploads, however, despite looking at all similar questions here on SO and also looking it up, I can't seem to get it to work.
This is my React form:
addUser (event) {
var formfile = new FormData();
formfile.append("file", this.state.filesToBeSent);
axios.post('adduser',
JSON.stringify({
entry: this.state.currname,
passwrd: this.state.currpasswrd,
formfile : formfile
}), {
headers: {"Content-Type": "application/json"}
}
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<form onSubmit={this.addUser} encType="multipart/form-data" >
<input value={this.state.currname} />
<input value={this.state.currpasswrd} />
<input type="file" value={this.state.filesToBeSent} name="file" />
<button type="submit" >Add</button>
</form>
);
}
This is my node.js file:
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var User = require('../models/User.js');
var bodyParser = require('body-parser');
var multer = require("multer");
const uuidv4 = require("uuid/v4");
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cd(null, "./uploads");
},
filename: (req, file, cb) => {
const newFilename = `${uuidv4()}${path.extname(file.originalname)}`;
cb(null, newFilename);
},
})
const upload = multer({ storage });
router.post("/", upload.single("file"), (req, res) => {
console.log(req.file + " and exit.");
});
module.exports = router;
I'm not doing anything with the text-inputs just yet, because I wanted to get the file upload to work first.
I tried out a variety of things, like using async(req, res) in router.post(). I tried using x-www-form-urlencoded as content-type and to only send the file without text-inputs( I specified formfile as data to be sent without the whole JSON.stringify(), however, I didn't manage to get it to work.
Can anyone spot a mistake in my code? Or does anyone have any other ideas about how to get it to work?
Edit:
Setting up the adduser-route in app.js:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var adduser = require('./routes/adduser');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/adduser', adduser);

Did you test your post endpoint? You can use a rest client such as Postman or Insomnia just to make sure that this is not the problem. Send a POST request to the endpoint and see if it gets invoked.
Then I guess you should use "/adduser" on your client and not "adduser" if you endpoint is exposed at "localhost:port/adduser". Your code doesn't show how you set up the route in the node.js code.
Finally you may want to use an higher level component to perform the upload, which can handle multipart for you in case you upload larger files. I found the combination react-dropzone + Multer being quite convenient.

try this :
router.post("/", upload.single("formfile"), (req, res) => {
console.log(req.formfile + " and exit.");
});

i think the headers should be:
{"Content-Type": "multipart/form-data"}
instead of application/json.

Related

Nodejs : req.body is empty when i try to upload a img file using jquery - ajax

i am learning nodejs and trying to upload a image file without page reload, i'm using this code below but it does not work. Req.body is empty. Can anyone help me ?
in my ejs file:
`````````````````
<body>
<form action="/" method='post' enctype="multipart/form-data" id='form-data'>
<input type="file" name='file' id='file' class='file'>
</form>
<script>
$(document).on('change', '#file', function () {
var property = document.getElementById('file').files[0];
var form_data = new FormData();
form_data.append('file', property);
$.post({
url: '/',
type: 'post',
data: form_data,
contentType: false,
cache: false,
processData: false,
success: function (data) {
console.log(data);
}
})
})
</script>
</body>
`````````````````
This is server.js:
const express = require('express');
const app = express();
const path = require('path');
app.set('view engine', 'ejs');
app.set('views' , __dirname);
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.urlencoded({ extended: true }));
app.post('/', (req,res) =>{
console.log(req.body)
})
app.get("/", (req,res) =>{
res.render('main');
})
app.listen(3000);
The easiest way I know to achieve what your aiming to do is with multer
Express doesn't easily handle files on its own, so by bringing multer in as a middleware you easily upload files. take a look at line 5 and see "dest", change that to wherever you want the files to be uploaded to
On line 12 I have added the middleware to the post route, the reason I have passed in 'file' is that the form data key for the file is 'file'
On line 13 I have change console.log from req.body to req.file as you can access the file information from there with multer
const express = require('express');
const app = express();
const path = require('path');
const multer = require('multer')
const upload = multer({ dest: './uploads/' })
app.set('view engine', 'ejs');
app.set('views' , __dirname);
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.urlencoded({ extended: true }));
app.post('/', upload.single('file'), (req,res) =>{
console.log(req.files)
})
app.get("/", (req,res) =>{
res.render('main');
})
app.listen(3000);
To install multer check out the link I have added or simply type:
npm install multer
Cheers,
Daniel
You need middleware for getting file or images for that install npm i multer for getting the file
app.js
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
app.post('/profile-img', upload.single('profileImage'), function (req, res, next) {
// req.file is the user profileImage.
// req.body will hold the other fields, if any
})
For mutiple images :
app.post('/product/images', upload.array('images', 12), function (req, res, next) {
// req.files is array of product images.
// req.body will contain the other fields, if any
})

Node Express 404 error when trying to load image uploaded by multer

Im trying to upload images with multer. Everything has worked before on localhost fine. Images get uploaded and i can view them from the url link the code provides. However once i have uploaded it on a server im starting to get this error : "Cannot GET /marketplace-api/rest-api/image/1650484814178.jpg".
I have not provided link to server/domains to the question in case people say thats the problem.
Here is my code:
const express = require('express');
const app = express();
const multer = require("multer");
const path = require("path");
const db = require('./db');
const cors = require('cors');
const port = 5000;
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true , limit: '50mb'}));
app.use(cors());
app.use("/image", express.static("image"));
let imageName = "";
const storage = multer.diskStorage({
destination: path.join("./image"),
filename: function (req, file, cb) {
imageName = Date.now() + path.extname(file.originalname);
cb(null, imageName);
},
});
const upload = multer({
storage: storage,
limits: { fileSize: 3000000 },
}).single("myImage");
app.post("/marketplace-api/rest-api/upload-image", (req, res) => {
upload(req, res, (err) => {
if (err) {
console.log(err);
} else {
return res.status(201)
.json({ url: "http://link to domains/marketplace-api/rest-api/image/" + imageName });
}
});
});
app.listen(port, () => {
console.log("server run in port", port);
});
ok, few things, 1. you dont have any get functions, which means you cant post to this location, i suggest doing this:
app.get('/', (req, res) => {
res.sendFile(__dirname + "/index.html");
});
and create a file called index.html, go on your site (localhost), and it should work, after that add a form in the html file, it should look something like this
<form action = "/marketplace-api/rest-api/upload-image" method = "POST">
<input type = "file" name="image">
<input type = "submit">
</form>
this will add a basic form where you can upload your photo.
there are a few more stuff to add / change, i will fix everything and make it a repo then send it here

Cant render EJS file as a Response to POST request

I've just started learning Express and Servers.
Problem
Just wanted to load another EJS page onto my localhost:4000/ path as a response after a POST request has been made for a form.
However, although I do get the response of the EJS page with the data from the req.body in the form from the client-side. I can't seem to get the page to load on the browser.
Any ideas? pls help
Express.js Server
let express = require('express');
let app = express();
let bodyParser = require('body-parser');
let path = require('path');
let fs = require('fs');
var urlencodedParser = bodyParser.urlencoded({extended:true});
app.use(express.json());
app.set('view engine', 'ejs');
app.use('/', express.static(__dirname + '/views'));
app.use('/', express.static(__dirname + '/views/partial'));
//Handling the GET request with the render of EJS file "index"
app.get('/', (req, res)=> {
res.render('index');
});
//Handling the POST request from the client, and sending the EJS file "createAccount" as a response
app.post('/', urlencodedParser, (req, res) => {
res.set('cache-control', 'max-age=0; private; no-cache');
res.render('createAccount', {data:req.body}); //
});
app.listen(4000, ()=>{
console.log('Port 4000 has been called');
});
EDIT:
I've included the JS file which I am using to make the POST request below.
document.querySelector('#btn').addEventListener('click', Master);
async function Master(){
console.log("Button clicked")
const username = document.querySelector("#username").value;
const password = document.querySelector("#password").value;
let results = {
"username": username,
"password": password
};
console.log(results);
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(results)
};
const post = await fetch('/', options);
};
I don't know if this is a correct question lol but is it ok to have the same "/" in get and post request? Why not put something in it.
app.post("/create")
then also change this
const post = await fetch('/create', options);

Postman Post request to NodeJS server does not give me the files properties

Good morning. I'm developing a portfolio app with projects. I did a mongoDB database and a NodeJS and express conexion to this database. I'm doing a controller with a method that allows me to upload a image to the database. I did this method, but when I use it with PostMan, the image is uploaded to the folder I indicate, but the files arguments don't appear and I need then to upload to the database.
I upload the code
Controller
uploadImage: function(req, res){
var projectId = req.params.id;
var fileName = "Imagen no subida...";
if(req.files){
return res.status(200).send({
files: req.files
});
}else{
return res.status(200).send({
message: fileName
});
}
}
Routes
'use strict'
var express = require('express');
var ProjectController = require('../controllers/project');
var router = express.Router();
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart({ uploadDir: './uploads' });
router.get('/home', ProjectController.home);
router.post('/test', ProjectController.test);
router.post('/save-project', ProjectController.saveProject);
router.get('/project/:id', ProjectController.getProject);
router.get('/projects', ProjectController.getProjects);
router.put('/project/:id', ProjectController.updateProject);
router.delete('/project/:id', ProjectController.deleteProject);
router.post('/upload-image/:id', multipartMiddleware ,ProjectController.uploadImage);
module.exports = router;
app.js
'use strict'
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// cargar archivo Rutas
var routes = require('./routes/project');
// Middlewares
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
// CORS
// Rutas
app.use('/api', routes);
// exportar
module.exports = app;
PostMan
I use form-data and I add an image.
Response:
{
"files": {}
}
I think in files JSON there are differents params to upload image to the dataBase, like filePath, fileName...
Thanks in advance
I think it should be req.files.file not req.files
If req.files.file does not exist, try to console.log(req), and console.log(req.files) to trace the file
Update
check that the Content-Type in the headers sections in postman is "multipart/form-data"
then you can find your file in req.files.image, as you name it image in form-data body section
hope it helps
thank you for your answer.
I did the two things, but when I do the console.log(req.files) the response is {}, and when I do console.log(req.files.file) the response is undefined.
I don't know what happens, I'm using a .jpg extension image.
Again thank you
thank you.
I send you an image of the PostMan request. I send you in i.stack because is the only way I can send the image.
[![[1]: https://i.stack.imgur.com/NHDog.png][1]][1]
The code:
// Multer
const storage = multer.diskStorage({
destination: function(req, res, cb){
cb(null, './uploads')
},
filename: function(req, file, cb){
cb(null, file.fieldname + "-" + Date.now())
}
})
const upload = multer({ storage: storage });
The function:
uploadImage: function(req, res, next){
console.log(req.file);
}
The request:
router.post('/upload-image/:id', upload.single('image'), ProjectController.uploadImage);

Get image sent from post in node.js

I need to use python to send an image through post and then download it on the node.js server side.
Python code:
import requests
from PIL import Image
import json
url = 'http://127.0.0.1:8080/ay'
files = {'file': open('image.jpg', 'rb')}
r = requests.post(url, data = files)
Node.js code:
var app = express();
app.use(bodyparser.json({ limit: '50mb' }));
app.use(bodyparser.urlencoded({ limit: '50mb', extended: true }));
app.post('/ay', function(req, res) {
var base64Data = req.body.file
require("fs").writeFile("out.png", base64Data, 'base64', function(err) {
console.log(err);
});
res.send('done');
});
But I can't seem to download the file properly on the server so I'm wondering what format python uses to open images and how I can fix the node.js code so that it can properly download the image.
Edit: there were a few issues with the code, I'm trying to use multer now but can't seem to get it working.
Python code:
import requests
url = 'http://127.0.0.1:8080/ay'
files = {'file': open('image.jpg', 'rb')}
r = requests.post(url, files = files)
Node.js code:
var express = require('express');
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express();
app.post('/ay', upload.single('avatar'), function (req, res, next) {
console.log(req.file)
res.send("done");
});
app.post('/ay', upload.array('photos', 12), function (req, res, next) {
console.log(req.files)
res.send("done");
});
I've tried both upload.single and upload.array but neither work.
So I finally figured it out using multer... incorrectly naming the key is why I couldn't use multer properly.
Python:
import requests
url = 'http://127.0.0.1:8080/ay'
files = {'file': open('image.jpg', 'rb')}
r = requests.post(url, files = files)
Node.js:
var express = require('express');
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express();
app.post('/ay', upload.array('file', 12), function (req, res, next) {
console.log(req.files)
res.send("done");
});
Have a look at this blog post which gives an example regarding how to access an uploaded file in node.js
In that example, after you load the bodyParser middleware, you have access to an object called req.files which contains the info regarding your uploaded file.
Do a console.log(req.files) and see what it displays.
The bodyParser middleware can be used to read uploaded files in Express v3, which is no longer maintained.
If you use v4 or above, you can use the connect-multiparty middleware, like this:
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
app.post('/ay', multipartMiddleware, function(req, resp) {
console.log(req.body, req.files);
// don't forget to delete all req.files when done
});
Also, I think your Python code is not uploading properly. Try with:
requests.post('http://127.0.0.1:8080/ay', files={'image.jpg': open('image.jpg', 'rb')})

Categories