I have a very simple form that is used to upload image file on the server's file system and render the image on the page. Apparent I can upload the image as expected but fail's to render the image. I get a broken image icon and
when I open the image location I get can't GET /uploads/undefined below is my code app.js, and index.ejs respectively
const express = require('express');
const multer = require('multer');
const ejs = require('ejs');
const path = require('path');
const port = 3000;
// Init app
const app = express()
// Set storage engine
const storage = multer.diskStorage({
destination: './public/uploads',
filename: function (req, file, cb) {
// null as first argument means no error
cb(null, Date.now() + '-' + file.originalname )
}
})
// Init upload
const upload = multer({
storage: storage,
limits: {
fileSize: 1000000
},
fileFilter: function (req, file, cb) {
sanitizeFile(file, cb);
}
}).single('files')
// Set view engine
app.set('view engine', 'ejs')
// Set static folder
app.use(express.static('./public'));
// Set the initial route
app.get('/', (req, res) => {
res.render('index');
})
// Handle the upload route
app.post('/upload', (req, res) => {
// res.send('done');
upload(req, res, (err) => {
if (err){
res.render('index', { msg: err})
}else{
// If file is not selected
if (req.file == undefined) {
res.render('index', { msg: 'No file selected!' })
}
else{
res.render('index', {
msg: 'File uploaded successfully!',
file: `uploads/${req.file.filname}`
});
}
}
})
})
function sanitizeFile(file, cb) {
// Define the allowed extension
let fileExts = ['png', 'jpg', 'jpeg', 'gif']
// Check allowed extensions
let isAllowedExt = fileExts.includes(file.originalname.split('.')[1].toLowerCase());
// Mime type must be an image
let isAllowedMimeType = file.mimetype.startsWith("image/")
if (isAllowedExt && isAllowedMimeType) {
return cb(null, true) // no errors
}
else {
// pass error msg to callback, which can be displaye in frontend
cb('Error: File type not allowed!')
}
}
app.listen(port, () => console.log('Server started at port : ' + port))
my index.ejs
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<title>Image Upload Demo</title>
</head>
<body>
<div class="container">
<h1>Image Upload</h1>
<%= typeof msg != 'undefined' ? msg : '' %>
<form method="POST" action="/upload" enctype="multipart/form-data">
<div class="file-field input-field">
<div class="btn grey">
<span>File</span>
<input name="files" type="file">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text">
</div>
</div>
<button type="submit" class="btn">Submit</button>
</form>
<br>
<img src="<%= typeof file != 'undefined' ? file : '' %>"class="img-responsive">
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>
You were so close! You just made a typo - req.file.filname should be req.file.filename in your upload handler.
Related
I'm having a go with the socket.io https://socket.io/get-started/chat, but my problem is that when i send message then the message cant automatically into chat box. i need to reload the page to view the chat that i sent. So how to make the chat automatically insert to chat box?. i already implement into my project. i already used socket.emit as you can see at then html file. is there the right way to put it?
server.js
var express = require('express');
var env = require('dotenv').config()
var ejs = require('ejs');
var path = require('path');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session)
const cookieParser = require('cookie-parser')
var http = require('http').Server(app);
var io = require('socket.io')(http);
var cors = require('cors')
app.use(cors())
app.use(cookieParser());
// mongodb://localhost:27017 127.0.0.1:27017
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://127.0.0.1:27017/findaprofessional', {
useNewUrlParser: true,
useUnifiedTopology: true
}, (err) => {
if (!err) {
console.log('MongoDB Connection Succeeded.');
} else {
console.log('Error in DB connection : ' + err);
}
});
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
});
const oneDay = 1000 * 60 * 60 * 24;
app.use(session({
secret: 'work hard',
saveUninitialized:true,
cookie: { maxAge: oneDay },
resave: true
}));
// ni lain
app.set("view engine", "ejs")
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/css', express.static(path.resolve(__dirname, "asset/css")))
app.use('/img', express.static(path.resolve(__dirname, "asset/img")))
app.use('/js', express.static(path.resolve(__dirname, "asset/js")))
app.use('/vendor', express.static(path.resolve(__dirname, "asset/vendor")))
app.use('/lib', express.static(path.resolve(__dirname, "asset/lib")))
app.use('/scss', express.static(path.resolve(__dirname, "asset/scss")))
app.use('/pic', express.static(path.resolve(__dirname, "asset/img/pic")))
var index = require('./routes/index');
const { Socket } = require('socket.io');
app.use('/', index);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('File Not Found');
err.status = 404;
next(err);
});
// error handler
// define as the last app.use callback
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.send(err.message);
});
io.on('connection', () =>{
console.log('a user is connected')
io.on("disconnect", function () {
console.log("user disconnected");
});
})
var server = http.listen(3000, () => {
console.log('Server is started on http://127.0.0.1:'+ server.address().port);
});
routing
// user chat
var http = require('http').Server(router);
var io = require('socket.io')(http);
// Render Message
router.get('/messages/:id', async function (req, res, next) {
user = await User.findOne({_id: req.session.userId}, {username: 1})
return res.render("user/messages.ejs", {user: user, booking: req.params.id});
});
// Display Message from DB
router.get('/messageslist/:booking', (req, res) => {
Message.find({booking: req.params.booking})
.populate({
path: "pro",
model: Pro,
}).populate({
path: "user",
model: User,
}).exec().then((data) => {
res.json(data)
})
})
router.get('/messages', (req, res) => {
Message.find({}, (err, messages) => {
res.send(messages);
})
})
router.post('/messages', async (req, res) => {
const {booking, user, message} = req.body
try {
var msg = new Message({
booking: booking,
message: message,
user: user
});
var savedMessage = await msg.save()
console.log('saved');
var censored = await Message.findOne({
message: 'badword'
});
if (censored)
await Message.remove({
_id: censored.id
})
else
io.emit('message', req.body);
res.sendStatus(200);
} catch (error) {
res.sendStatus(500);
return console.log('error', error);
} finally {
console.log('Message Posted')
}
})
HTML
<!DOCTYPE html>
<html lang="en">
<%- include("../header.ejs") %>
<head>
<link href="/css/sb-admin-2.min.css" rel="stylesheet">
<link href="/css/chat.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"
integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous">
</script>
</script>
<script src="/socket.io/socket.io.js"></script>
</head>
</head>
<!-- start here! -->
<section class="msger" style="margin: auto;">
<header class="msger-header">
<div class="msger-header-title">
<i class="fas fa-comment-alt"></i> Chat
</div>
<div class="msger-header-options">
<span><i class="fas fa-cog"></i></span>
</div>
</header>
<main class="msger-chat">
</main>
<form class="msger-inputarea">
<input type="hidden" name="booking" value="<%= booking %>">
<input type="hidden" id="name" class="form-control" readonly placeholder="Name"
value="<%= user.username %>">
<input type="text" name="user" value="<%= user._id %>">
<input id="message" type="text" class="msger-input" placeholder="Enter your message...">
<button id="send" type="submit" class="msger-send-btn">Send</button>
</form>
</section>
<!-- End of Main Content -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
</div>
<!-- End of Main Content -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Bootstrap core JavaScript-->
<script src="/vendor/jquery/jquery.min.js"></script>
<script src="/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="/vendor/datatables/jquery.dataTables.min.js"></script>
<script src="/vendor/datatables/dataTables.bootstrap4.min.js"></script>
<!-- Page level custom scripts -->
<script src="/js/demo/datatables-demo.js"></script>
<script type="text/javascript" src="/js/mdb.min.js"></script>
<!-- Custom scripts -->
<script>
var socket = io();
$(() => {
$("#send").click(() => {
sendMessage({
booking: $("input[name=booking]").val(),
user: $("input[name=user]").val(),
message: $("#message").val()
});
})
getMessages()
})
socket.on('message', addMessages)
socket.on('message', getMessages)
socket.emit('message', getMessages)
socket.emit('message', addMessages)
function addMessages(message) {
if(message.user && message.user != '') {
if($("input[name=user]").val() == message.user._id) {
html = '<div class="msg right-msg"><div class="msg-img" style="background-image: url('+message.user.image +')"></div>'
html += '<div class="msg-bubble"><div class="msg-info"><div class="msg-info-name">' + message.user.username + '</div><div class="msg-info-time">' + message.createdAt + '</div></div>'
}
}
else {
html = '<div class="msg left-msg"><div class="msg-img" style="background-image: url('+message.pro.image +')"></div>'
html += '<div class="msg-bubble"><div class="msg-info"><div class="msg-info-name">' + message.pro.username + '</div><div class="msg-info-time">' + message.createdAt + '</div></div>'
}
html += '<div class="msg-text">' + message.message + '</div></div></div>'
$(".msger-chat").append(html)
}
function getMessages() {
$.get('http://localhost:3000/messageslist/<%=booking%>', (data) => {
data.forEach(addMessages);
})
}
function sendMessage(message) {
$.post('http://localhost:3000/messages', message)
}
</script>
i tried to automatically get the message without reload the page but it doenst work. Can anyone see where the problem is?
From what I know, the default behavior when you click a button with type submit inside a form, it tries to reload the page even though you haven't defined any function or other page for it to go.
You would have to get the submit event from the form and use the preventDefault() funciton for this event, check out this thread for more info:
JavaScript code to stop form submission
So you would stop the form submission and then get new messages for the page, executing the javascript to add the new messages to the page by manipulating the DOM.
You can write socker.write() method for accessing real time messages in nodejs.
I want to upload a file using NodeJS streams and HTML forms. I have a simple server.
It is working when I upload the file using Postman. But when I upload through HTML form, the file is uploaded but is not readable. How to do it?
This is index.js:
const app = require('express')();
const fs = require('fs');
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
app.post('/file-upload', (req, res) => {
const filePath = 'uploads/uploaded-file';
const stream = fs.createWriteStream(filePath);
req.pipe(stream);
stream.on('close', () => {
res.send({ status: 'success', filePath })
});
});
// Start server
app.listen(3000, () => console.log("The server is running at localhost:3000"));
This is index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<h1>File Upload</h1>
<form method="post" action="/file-upload" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" name="upload">
</form>
</body>
</html>
This is the postman request screenshot:
As you can see you're trying to upload the file through a form using multipart/form-data whereas you're uploading it as binary in postman.
To fix this you can setup up a multipart/form-data parser on your server side (e.g. using multer), which would look something like this:
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
// ...
app.post('/file-upload', upload.single('file'), (req, res) => {
res.send({ status: 'success', filePath: req.file.path })
});
I am working on an Image Upload server using multer and mongodb following This GeeksForGeeks Post:
https://www.geeksforgeeks.org/upload-and-retrieve-image-on-mongodb-using-mongoose/
I did everything same as in this post but my localhost server is just loading and loading.
My Project Structure :
https://i.stack.imgur.com/p1NhC.png
App.js:
// Step 1 - set up express & mongoose
var express = require('express')
var app = express()
var bodyParser = require('body-parser');
var mongoose = require('mongoose')
var fs = require('fs');
var path = require('path');
require('dotenv/config');
// Step 2 - connect to the database
mongoose.connect(process.env.MONGO_URL,
{ useNewUrlParser: true, useUnifiedTopology: true }, err => {
console.log('connected')
});
// Step 3 - code was added to ./models.js
// Step 4 - set up EJS
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// Set EJS as templating engine
app.set("view engine", "ejs");
// Step 5 - set up multer for storing uploaded files
var multer = require('multer');
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads')
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now())
}
});
var upload = multer({ storage: storage });
// Step 6 - load the mongoose model for Image
var imgModel = require('./model');
// Step 7 - the GET request handler that provides the HTML UI
app.get('/', (req, res) => {
imgModel.find({}, (err, items) => {
if (err) {
console.log(err);
res.status(500).send('An error occurred', err);
}
else {
res.render('imagesPage', { items: items });
}
});
});
// Step 8 - the POST handler for processing the uploaded file
app.post('/', upload.single('image'), (req, res, next) => {
var obj = {
name: req.body.name,
desc: req.body.desc,
img: {
data: fs.readFileSync(path.join(__dirname + '/uploads/' + req.file.filename)),
contentType: 'image/png'
}
}
imgModel.create(obj, (err, item) => {
if (err) {
console.log(err);
}
else {
// item.save();
res.redirect('/');
}
});
});
// Step 9 - configure the server's port
var port = process.env.PORT || '3000'
app.listen(port, err => {
if (err)
throw err
console.log('Server listening on port', port)
})
Model.js:
// Step 3 - this is the code for ./models.js
var mongoose = require('mongoose');
var imageSchema = new mongoose.Schema({
name: String,
desc: String,
img:
{
data: Buffer,
contentType: String
}
});
//Image is a model which has a schema imageSchema
module.exports = new mongoose.model('Image', imageSchema);
.env:
MONGO_URL = mongodb://localhost/mongo
PORT = 5500
imagesPage.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Uploading</title>
</head>
<body>
<h1>To Upload Image on mongoDB</h1>
<hr>
<div>
<form action="/" method="POST" enctype="multipart/form-data">
<div>
<label for="name">Image Title</label>
<input type="text" id="name" placeholder="Name"
value="" name="name" required>
</div>
<div>
<label for="desc">Image Description</label>
<textarea id="desc" name="desc" value="" rows="2"
placeholder="Description" required>
</textarea>
</div>
<div>
<label for="image">Upload Image</label>
<input type="file" id="image"
name="image" value="" required>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>
<hr>
<h1>Uploaded Images</h1>
<div>
<% items.forEach(function(image) { %>
<div>
<div>
<img src="data:image/<%=image.img.contentType%>;base64,
<%=image.img.data.toString('base64')%>">
<div>
<h5><%= image.name %></h5>
<p><%= image.desc %></p>
</div>
</div>
</div>
<% }) %>
</div>
</body>
</html>
Please tell what i am doing wrong.
I very new to backend so I don't know what to do
Thanks
Here, there is middleware for uploading and storing image file. I have uploaded in mongoDB using mongoose library. Here I want to allow only docx file to upload and uploading other file type shows "Invalid filetype". How can I assign mimetype in such a way that it accepts only the docx file?
middleware.js
const util = require("util");
const multer = require("multer");
const GridFsStorage = require("multer-gridfs-storage");
const mongoose = require('mongoose');
const Grid = require('gridfs-stream');
const mongoURI ='mongodb://localhost:27017/file_uploaded';
const promise = mongoose.connect(mongoURI, { useNewUrlParser: true });
const conn = mongoose.connection;
let gfs;
conn.once('open',() => {
gfs = Grid(conn, mongoose.mongo);
gfs.collection('uploads');
});
var storage = new GridFsStorage({
db: promise,
options: {useNewUrlParser: true, useUnifiedTopology: true },
file: (req, file) => {
const match = ["image/png", "image/jpeg"];
if (match.indexOf(file.mimetype)===-1) {
const filename = `${Date.now()}-bezkoder-${file.originalname}`;
return filename;
}
return {
bucketName: "photos",
filename: `${Date.now()}-bezkoder-${file.originamname}`
};
}
});
var uploadFile = multer({storage: storage}).single("file");
var uploadFilesMiddleware = util.promisify(uploadFile);
module.exports = uploadFilesMiddleware;
upload.js
This is the controller for uploading image.
const upload = require("../middleware/middleware");
const uploadFile = async(req,res) => {
try {
await upload(req,res);
console.log(req.file);
if (req.file == undefined) {
return res.send('You must select a file');
}
return res.send('File has been uploaded.');
} catch(error) {
console.log(error);
return res.send(`Error when trying upload image: ${error}`);
}
};
module.exports = {
uploadFile: uploadFile
};
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Node.js upload images</title>
</head>
<body>
<h4>Node.js upload images - bezkoder.com</h4>
<form class="mt-4"
action="/upload"
method="POST"
enctype="multipart/form-data"
>
<div class="form-group">
<input
type="file"
name="file"
id="input-files"
class="form-control-file border"
/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<hr />
</body>
</html>
If you want only specific file type. Check inside file option and reject error.
const express = require('express');
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const url = 'mongodb://localhost:27017/files';
const storage = new GridFsStorage({
url: url,
options: {useUnifiedTopology: true},
file: (req, file) => {
return new Promise((resolve, reject) => {
if (file.mimetype === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
resolve({
bucketName: 'words'
})
} else {
reject(Error("File type has been rejected"));
}
});
}
});
const upload = multer({ storage });
const app = express();
app.get('/', (req, res, next) => {
res.sendFile(__dirname+"/index.html")
});
app.post('/file', upload.single('file'), (req, res, next) => {
res.send(req.file)
});
app.listen(3333);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form enctype="multipart/form-data" action="/file" method="post">
<div>
<label>Select a file:</label>
<input type="file" name="file" />
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</body>
<form action="http://localhost:3000/examples" method="post" enctype="multipart/form-data" accept="application/json">
<input type="text" name ="name">
<input type="text" name ="codedescription">
<input type="file" name ="file">
<input type="submit" value="Upload selected file to server">
</form>
var multer = require('multer');
app.use(multer({ dest: './uploads/',
onFileUploadStart : function(file){
console.log('File recieved:');
console.log(file);
},
onFileUploadData:function (file,data){
console.log('Data recieved');
},
onParseEnd: function(req,next){
next();
}
}));
app.route('/examples').post(users.requiresLogin, examples.create);
exports.create = function(req, res) {
console.log("req.files"+req.files);
console.log("req.name"+req.body.name);
console.log("req.codedescription"+req.body.codedescription);
};
Submit form without enctype="multipart/form-data" is working but I can not get files.
Submit form with enctype="multipart/form-data" is working but I can not get files as well as data.
you can try this
<html>
<head>
<title>FileUpload</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
<form id = "uploadForm"
enctype = "multipart/form-data"
action = "http://localhost:3000/api/photo"
method = "post"
>
<input type="file" name="userPhoto" multiple />
<input type="submit" value="Upload Image" name="submit" id="btnUpload">
<span id="spnStatus" />
</form>
<script>
$(document).ready(function(){
$('#btnUpload').click(function(){
$('#spnStatus').empty().text("File is Uploading");
$(this).ajaxSubmit({
error : function(xhr){
status('Error : '+xhr.status);
}
success : function(response){
$('#spnStatus').empty().text(xhr);
}
});
});
});
</script>
</body>
</html>
NodeJS Express
var express = require("../node_modules/express");
var multer = require('../node_modules/multer');
var bodyParser = require("../node_modules/body-parser");
var app = express();
app.use(bodyParser.json());
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage }).array('userPhoto',8);
app.get('/',function(req,res){
res.sendFile(__dirname + "/fileUpload.html");
});
app.post('/api/photo',function(req,res){
upload(req,res,function(err) {
if(err) {
console.log(err);
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
app.listen(3001,function(){
console.log("Working on port 3001");
});
Now you can upload upto 8 files at a time, if you want to upload more than eight, just edit var upload = multer({ storage : storage }).array('userPhoto','LIMITHERE');
#karthik comment, i think you need this as well including after jquery, when you want to use his example:
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.min.js"></script>