NodeJS & express file upload with XMLHttpRequest - not working - node.js

I am uploading a file using this form and by the time xhr submits it the server does not recognize req.xhr === true, as such I can not process the file upload. What am I missing?
<form encType="multipart/form-data" method="post">
<Button onClick={(event)=>startUploadFile(event)} type="button">Upload</Button>
<input type="file" name="file" id="file" multiple="multiple" onChange={onChangeHandler} />
</form>
Client side
const [upFile, setUpFile] = useState('')
const onChangeHandler = event => {
setUpFile(event.target.files[0]);
}
const startUploadFile = e => {
setSpin('visible')
setMsg(`Uploading Media ...`)
e.preventDefault()
const data = new FormData()
data.append('file', upFile)
var formData = new FormData();
var xhr = new XMLHttpRequest();
var onProgress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded/e.total)*100;
console.log('percentage = ' + percentComplete)
}
};
formData.append('files', upFile); // this is a state object set onChange
xhr.open('post', '/upload', true);
xhr.addEventListener('error', onError, false);
xhr.addEventListener('progress', onProgress, false);
xhr.send(formData);
xhr.addEventListener('readystatechange', onReady, false);
}
Server side
const express = require('express'),
app = express.Router(),
cors = require('cors'),
fs = require('fs-extra');
app.use(cors())
app.post('/uploadFile', (req, res) => {
if (req.xhr || req.headers.accept.indexOf('json') > -1) {
// not accepted (req.xhr is false always) why?
}
});

In expressjs you need to install multer or formidable package to upload file from client side application then you will receive your file in req.files object.

Thanks to #Nikas for the remarks - here is working solution if anyone needs it or something like it.
For the client side:
const startUploadFile = e => {
setSpin('visible')
setMsg(`Uploading Media ...`)
e.preventDefault()
const data = new FormData()
data.append('file', upFile)
var formData = new FormData();
var xhr = new XMLHttpRequest();
var onProgress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded/e.total)*100;
console.log('% uploaded:' + percentComplete)
}
};
var onReady = function(e) {
console.log('ready')
};
var onError = function(err) {
console.log('something went wrong with upload');
};
formData.append('files', upFile); // this is a state object set onChange
xhr.open('post', '/media/uploadFile', true);
xhr.addEventListener('error', onError, false);
xhr.addEventListener('progress', onProgress, false);
xhr.send(formData);
xhr.addEventListener('readystatechange', onReady, false);
}
server side:
const express = require('express'),
app = express.Router(),
cors = require('cors'),
fs = require('fs-extra'),
formidable = require('formidable');
app.post('/uploadFile', (req, res) => {
const path = './client/public/upload/';
var form = new formidable.IncomingForm();
form.uploadDir = path;
form.encoding = 'binary';
form.parse(req, function(err, fields, files) {
if (err) {
console.log(err);
res.send('upload failed')
} else {
var oldpath = files.files.path;
var newpath = path + files.files.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.send('complete').end();
});
}
});
})

Related

Images uploaded with node corrupted

Images I upload via Next.js API routes are corrupted. I am using Formidable.
From my React component I'm submitting a form via these functions:
const fileUpload = async (file: File) => {
const url = '/api/image'
const formData = new FormData()
formData.append('file', file)
const config = {
headers: {
'content-type': 'multipart/form-data',
},
}
const response = await axios.post(url, formData, config)
const { data } = response
return data
}
const handleSubmit = async (event: React.SyntheticEvent) => {
const url = '/api/post'
if (files) {
// ignore
fileUpload(files[0]).then((response) =>
console.log('submit response', response)
)
}
event.preventDefault()
}
And the API route in Next looks like this:
import formidable from 'formidable'
const fs = require('fs')
const { BlobServiceClient } = require('#azure/storage-blob')
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
const AZURE_STORAGE_CONNECTION_STRING =
process.env.AZURE_STORAGE_CONNECTION_STRING
export const config = {
api: {
bodyParser: false,
},
}
const getBlobName = (originalName) => {
const identifier = Math.random().toString().replace(/0\./, '')
return `${identifier}-${originalName}`
}
export default async (req, res) => {
const form = new formidable.IncomingForm()
form.keepExtensions = true
form.uploadDir = './public/static/uploads'
form.parse(req, async (err, fields, files) => {
if (err) {
return
}
return res.json({ fields, files })
})
form.on('file', async (name, file) => {
const blobServiceClient = await BlobServiceClient.fromConnectionString(
AZURE_STORAGE_CONNECTION_STRING
)
const containerClient = await blobServiceClient.getContainerClient(
'images'
)
const buff = fs.readFileSync(file.path)
const data = buff.toString('base64')
const blobName = getBlobName(file.name)
const blockBlobClient = containerClient.getBlockBlobClient(blobName)
blockBlobClient.upload(data, data.length)
})
}
The image which gets stored locally is corrupt and looks like a TV tuned to a dead channel. I'm clearly not encoding it properly — but unsure whether it's my ContentType or the string encoding?
I believe the problem is coming because you're converting the data into a base64 encoded string:
const data = buff.toString('base64')
Considering you're already saving the uploaded file somewhere on the server (this is done by formidable package), please try something like:
const blobName = getBlobName(file.name)
const blockBlobClient = containerClient.getBlockBlobClient(blobName)
blockBlobClient.uploadFile(file.path)
uploadFile() method reference: https://learn.microsoft.com/en-gb/javascript/api/#azure/storage-blob/blockblobclient?view=azure-node-latest#uploadfile-string--blockblobparalleluploadoptions-.
UPDATE
Please try this code. I just tried this code and was able to upload the file successfully. When I downloaded the file, it was not corrupted.
form.on('file', async (name, file) => {
const blobServiceClient = await BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
const containerClient = await blobServiceClient.getContainerClient('images');
const blobName = file.name;
const contentType = file.type;
const filePath = file.path;
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.uploadFile(file.path);
});
UPDATE #2
Here's the complete code I used:
<form id="form1" method="post" action="/upload" enctype="multipart/form-data">
<input name="file" type="file" id="file1" accept="image/*"/>
<input type="button" id="button1" value="Upload" />
</form>
<script src="https://code.jquery.com/jquery-1.12.4.js" integrity="sha256-Qw82+bXyGq6MydymqBxNPYTaUXXq7c8v3CwiYwLLNXU=" crossorigin="anonymous"></script>
<script>
$(document).on('ready', function() {
});
$('#button1').on('click', function(e) {
data = new FormData();
console.log($('#file1')[0].files[0]);
data.append('file', $('#file1')[0].files[0]);
console.log(data);
$.ajax({
url: '/upload',
data: data,
processData: false,
contentType: false,
type: 'POST',
success: function ( data ) {
alert( data );
}
});
e.preventDefault();
e.stopPropagation();
});
</script>
var express = require('express'),
path = require('path'),
fs = require('fs'),
formidable = require('formidable');
const { BlobServiceClient } = require('#azure/storage-blob');
var app = express();
app.set('port', (process.env.PORT || 5000));
// Tell express to serve static files from the following directories
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
app.listen(app.get('port'), function() {
console.log('Express started at port ' + app.get('port'));
});
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.post('/upload', function(req, res) {
const connectionString = 'DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key;EndpointSuffix=core.windows.net;';
const container = 'container-name';
let form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir = './public/static/uploads';
form.parse(req, async function (err, fields, files) {
});
form.on('file', async (name, file) => {
const blobServiceClient = await BlobServiceClient.fromConnectionString(connectionString);
const containerClient = await blobServiceClient.getContainerClient(container);
const blobName = file.name;
const contentType = file.type;
const filePath = file.path;
console.log(file);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.uploadFile(file.path);
console.log(uploadBlobResponse);
});
});

Node.js Multer doesn't save image on my project folder

I've have to do some maintenace on a Node.js project, and I can't get to upload a image.
I've already seen many post about uploading images into node.js but I can't figure out what happening with my code.
my routes/index.js (like my app.js)
var keystone = require("keystone");
var middleware = require("./middleware");
var importRoutes = keystone.importer(__dirname);
// Common Middleware
keystone.pre("routes", middleware.initLocals);
keystone.pre("render", middleware.flashMessages);
// Import Route Controllers
var routes = {
views: importRoutes("./views")
};
// Setup Route Bindings
exports = module.exports = function (app) {
// Views
app.get("/", routes.views.index);
app.all("/cadastroEvento", routes.views.cadastroEvento);
};
my routes/views/cadastroEvento
var keystone = require("keystone");
var async = require("async");
var env = require("../env");
var Cloudant = require("cloudant");
var multer = require("multer");
var upload = multer({ dest : "/" }).single("file");
// Conexão com o MongoDB
var Evento = keystone.list("Evento");
var mongoDb = require("mongodb");
var MongoClient = mongoDb.MongoClient;
var urlDb = env.urlDb;
exports = module.exports = function (req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
var url = view.req.originalUrl;
locals.tipo = url.substr(url.indexOf("?") + 1);
locals.section = "cadastroEvento";
locals.formData = req.body || {};
locals.validationErrors = {};
// POST
view.on("post", { action : "cadastroEvento" }, function (next) {
// Seta campos para mensagem de erro
locals.erroNome = false;
locals.erroDataInicio = false;
locals.erroDataFim = false;
locals.erroAoSalvar = false;
locals.erroAoConectar = false;
locals.eventoCadastrado = false;
locals.erroValidacao = false;
// Valida os campos
var validacao = validaCampos(req);
// HERE I DO THE UPLOAD OF THE IMAGE
upload(req, res, function(err)
{
if(err) {
return res.end("Error uploading file." + err);
}
res.end("File is uploaded");
});
console.log("Files: " + JSON.stringify(req.files));
... REST OF CODE NOT RELATED TO THE IMAGE UPLOAD ...
};
In my cadastroEvento.jade I have a form with method='post' enctype="multipart/form-data" and a input type="file" and name="file"
After the post, i receive the message: "File is uploaded"
but no image appears in my folder...
My
console.log("Files: " + JSON.stringify(req.files)); returns this:
Files: {"file":{"fieldname":"file","originalname":"Screenshot_2.png","name":"47707bab7b0b7bf03a882e88f5a0715d.png","encoding":"7bit","mimetype":"image/png","path":"C:\\Users\\JOS-HI~1\\AppData\\Local\\Temp\\47707bab7b0b7bf03a882e88f5a0715d.png","extension":"png","size":7895,"truncated":false,"buffer":null}}
Any help on where is my error would be appreciated.
Thanks

Multiple image upload using Node.js

I am working on Node.js and trying to handle multiple image.
I am using following code to upload a single image and then saving the path in string format to the database.
var multiparty = require("multiparty");
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var img = files.image[0];
var fs = require('fs');
fs.readFile(img.path, function(err, data) {
var path = "/path/to/upload/" + img.originalFilename;
fs.writeFile(path, data, function(error) {
if (error) console.log(error);
});
});
})
Now how to handle multiple image.
Any help will be appreciated!
var express = require('express'),
app = express(),
formidable = require('formidable'),
util = require('util'),
fs = require('fs-extra'),
bodyparser=require('body-parser'),
qt = require('quickthumb'),
path = require('path');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/db');
var Images = require('./model.js');
app.use(qt.static(__dirname + '/'));
app.use(bodyparser());
app.set('view engine','ejs');
app.post('/upload',function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
});
form.on('field',function(name,value){
});
form.on('end', function(fields, files) {
for(var x in this.openedFiles)
{
//Images is my model
var img = new Images();
var temp_path = this.openedFiles[x].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[x].name;
//console.log('file '+file_name);
img.size = this.openedFiles[x].size;
img.type = this.openedFiles[x].type;
/* Location where we want to copy the uploaded file */
var new_location = 'uploads/';
console.log(img.nam=new_location+file_name);
img.save(function(err,imgobj) {
if (err)
throw err;
});
//to copy the file into a folder
fs.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.log(err);
}
});//fscopy
}//for loop
});//form end
res.send('Done!!');
});//post
app.listen(3000);
console.log('started server');

File upload in node.js

I want to upload my file in my workspace and read it in node.js.
Html code:
<html>
<head>
<script src = "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body>
<div ng-app="" ng-controller="SalesImportControl">
<form ng-submit="readCustomer()">
<input type="file" name="file" file-model = "myFile">
<br>
<button type="submit" >Submit</button>
</form>
</div>
</body>
</html>
Controller:
'use strict';
angular.module('app')
.controller('SalesImportControl', ['$scope','$http', '$location', '$rootScope','fileUpload' , function($scope, $http, $location, $rootScope,fileUpload) {
console.log(" In dataimportCtrl");
//customer
$scope.readCustomer = function(req,res){
var file1=$scope.myFile;
var fl1 = $scope.myFile.name;
console.log("file name:"+$scope.myFile.name);
var uploadUrl = "/fileUpload";
var fd = new FormData();
fd.append('file', file1);
//File upload
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function(data){
}).error(function(){
});
//sales
$http.post('/salesimport', { params: fl1 }).success(function(data) {
console.log("in controller1");
console.log("controller:"+data);
$scope.data=data["jarr"];
$scope.data1=data["jarr1"];
$scope.data2=data["jarr2"];
$scope.data3=data["jarr3"];
$scope.data4=data["jarr4"];
}).error(function(response) {
console.error("error in posting");
});
};
}])
Server.js:
var express = require('express');
var bodyparser = require('body-parser');
var mysql = require('mysql');
var app = express();
var formidable = require('formidable');
var path = require('path');
var fs = require('fs');
var _ = require('underscore');
var vouchersmodel = require('./models/v_db.js');
app.use(express.static(__dirname + "/public/angular"));
app.use(bodyparser.json());
app.listen(3000);
console.log('Server running on 3000');
app.post('/fileUpload', function (req, res) {
var form = new formidable.IncomingForm();
//Formidable uploads to operating systems tmp dir by default
form.uploadDir = __dirname+"/models/upload2/"; //set upload directory
form.keepExtensions = true; //keep file extension
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/xml'});
res.write('received upload:\n\n');
console.log("form.bytesReceived");
console.log("file size: "+JSON.stringify(files.file.size));
console.log("file path: "+JSON.stringify(files.file.path));
console.log("file name: "+JSON.stringify(files.file.name));
console.log("file type: "+JSON.stringify(files.file.type));
console.log("astModifiedDate:"+JSON.stringify(files.file.lastModifiedDate));
console.log("file:"+JSON.stringify(files.file));
vouchersmodel.upload(files.file.path,files.file.name, function (msg) {
return res.json(msg);
});
});
});
Model:
exports.upload= function(r,name,callback){
var fs = require('fs');
var newPath = __dirname + "/upload2/"+name;
fs.readFile(r, function (err, data) {
fs.writeFile(newPath,data, function (err,res) {
if(!err){
console.log("uploaded.........");
callback();
}
});
});
}
My question is it uploads the file but before uploading the file it runs the salesimport post method in controller and shows no such directory error.
Where I am wrong ?
Note:
salesimport post method request accesses the file uploaded in model.

How To Upload Multiple Image from Android to NodeJS server

I recently saw a tutorial to upload some photos from here [https://aguacatelang.wordpress.com/2012/08/19/android-multipart-upload-to-node-js/][1]
I've just learned nodejs and less understanding of the structure of programming languages, I found a mistake like this :
home/je/Documents/BE/UploadFoto/app.js:12
var db = new Db('photos', new dbServer('localhost', dbConnection.'27017', {}))
^^^^^^^
SyntaxError: Unexpected string
at Module._compile (module.js:439:25)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:935:3
this is original source code :
var express = require('express');
var app = express()
var fs = require('fs');
var im = require('imagemagick');
var Db = require('mongodb').Db;
var dbServer = require('mongodb').Server;
var dbConnection = require('mongodb').Connection;
var db = new Db('photos', new dbServer('localhost', dbConnection.'DEFAULT_PORT', {}));
db.open(function(err, db){});
app.use(express.bodyParser())
app.get('/', function(req, res){
res.send(
'<form action="/upload" method="post" enctype="multipart/form-data">'+
'<input type="file" name="source">'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.post('/upload', function(req, res){
console.log("Received file:\n" + JSON.stringify(req.files));
var photoDir = __dirname+"/photos/";
var thumbnailsDir = __dirname+"/photos/thumbnails/";
var photoName = req.files.source.name;
fs.rename(
req.files.source.path,
photoDir+photoName,
function(err){
if(err != null){
console.log(err)
res.send({error:"Server Writting No Good"});
} else {
im.resize(
{
srcData:fs.readFileSync(photoDir+photoName, 'binary'),
width:256
},
function(err, stdout, stderr){
if(err != null){
console.log('stdout : '+stdout)
res.send({error:"Resizeing No Good"});
} else {
//console.log('ELSE stdout : '+stdout)
fs.writeFileSync(thumbnailsDir+"thumb_"+photoName, stdout, 'binary');
res.send("Ok");
}
}
);
}
}
);
});
app.get('/info', function(req, res){
console.log(__dirname);
res.send("ok");
});
app.listen(8000);
console.log('connected to localhost....')
I switched DEFAULT_PORT to 27017 because in my PC the port that is used mongodb:localhost/27017. May someone help me? thanks
BodyParser no longer supports parsing multypart requests. You should try using one of these modules.
busboy.
multiparty.
formidable.
multer.
Here is a simple example using multiparty:
var multipart = require('multiparty');
app.post('/upload', function(req, res){
var form = new multipart.Form();
form.parse(req, function(err, fields, files) {
console.log(files);//list all files uploaded
//put in here all the logic applied to your files.
});
return;
});
Or you can use it as a middleware, like this:
var multipart = require('connect-multiparty');
app.use(multipart());
app.post('/upload', function(req, res) {
console.log(req.files);//list all files uploaded
// apply all logic here
});
I am sending files like Audios,Images and videos etc from Android Using Retrofit ,At server side i am using node.js .
on btnUpload click i am uploading my files to server .
btnUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(MusicActivity.this, ""+ commonAdapter.getSelectedItems().size(), Toast.LENGTH_SHORT).show();
String fileUri=null;
File file=null;
RequestBody requestFile=null;
MultipartBody.Part part=null;
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
for(int i=0;i<commonAdapter.getSelectedItems().size();i++)
{
fileUri = commonAdapter.getSelectedItems().get(i);
file = new File(fileUri);
requestFile = RequestBody.create(MediaType.parse(fileUri), file);
//music name must be same as music at node.js ,
//if its different then it will not worked.
part = MultipartBody.Part.createFormData("music", file.getName(), requestFile);
Call<UploadObject> myResponseCall = apiService.uploadMusic(part);
myResponseCall.enqueue(new Callback<UploadObject>() {
#Override
public void onResponse(Call<UploadObject> call, Response<UploadObject> response) {
Log.d("kkkk","ok response");
}
#Override
public void onFailure(Call<UploadObject> call, Throwable t) {
// Toast.makeText(ImagesActivity.this, "Error Occured ! ", Toast.LENGTH_LONG).show();
Log.d("kkkk","on failed");
}
});
}
}
});
My ApiInterface for Retrofit
public interface ApiInterface {
#Multipart
#POST("api/uploadImage")
Call<UploadObject> uploadImage(#Part MultipartBody.Part file);
#Multipart
#POST("api/uploadVideo")
Call<UploadObject> uploadVideo(#Part MultipartBody.Part file);
#Multipart
#POST("api/uploadMusic")
Call<UploadObject> uploadMusic(#Part MultipartBody.Part file);
}
Its my getSelectedItem :- which return selected Items
public ArrayList<String> getSelectedItems()
{
return selectedItems;
}
At Node.js I am using multer
var express = require('express')
//const bodyParser = require('body-parser');
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var fs = require('fs');
var app = express()
// app.use(bodyParser.json());
// app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/uploadImage', upload.single('image'), function (req, res, next) {
var tmp_path = req.file.path;
var target_path = 'uploads/' + req.file.originalname;
/** A better way to copy the uploaded file. **/
var src = fs.createReadStream(tmp_path);
var dest = fs.createWriteStream(target_path);
src.pipe(dest);
src.on('end', function() { console.log('complete') });
src.on('error', function(err) { console.log('error'); });
fs.unlink(tmp_path);
});
app.post('/api/uploadVideo', upload.single('video'), function (req, res, next) {
var tmp_path = req.file.path;
var target_path = 'uploads/' + req.file.originalname;
/** A better way to copy the uploaded file. **/
var src = fs.createReadStream(tmp_path);
var dest = fs.createWriteStream(target_path);
src.pipe(dest);
src.on('end', function() { console.log('complete') });
src.on('error', function(err) { console.log('error'); });
fs.unlink(tmp_path);
});
app.post('/api/uploadMusic', upload.single('music'), function (req, res, next) {
var tmp_path = req.file.path;
var target_path = 'uploads/' + req.file.originalname;
/** A better way to copy the uploaded file. **/
var src = fs.createReadStream(tmp_path);
var dest = fs.createWriteStream(target_path);
src.pipe(dest);
src.on('end', function() { console.log('complete') });
src.on('error', function(err) { console.log('error'); });
fs.unlink(tmp_path);
});
app.listen(8080,(res,err)=>{
if(err)
console.log('error occured while connecting port');
else
console.log('Server is Up');
});
I hope its help You!

Resources