Seems like many people have ran into similar kind of problem but googling hasn't helped me so far. I'm trying to serve the file to the user and automatically prompt download on client side, but all I'm getting is "The image cannot be displayed because it contains errors.
Here is my client side code:
function downloadFile(passcode){
console.log(passcode);
const payload = {"password" : passcode.toLowerCase()}
axios.post(downloadUrl, payload, {
headers : {'Content-Type' : 'application/json'}
})
.then((res) => {
console.log(res.data)
window.open(downloadUrl + '/' + res.data)
})
}
So the user types in a passcode, and clicks on the download button and should get the appropriate file. New tab opens but file doesn't stard downloading.
Here is my server side:
const getFilePath = async (req, res) => {
const passcode = req.body.password
try {
fs.readdir(path.join(homeDir + '/uploads/' + passcode), 'utf-8',(err, files) => {
files.forEach((file) => {
const filename = passcode + '/' + file
try {
res.send(filename)
res.end()
} catch (error) {
console.log(error);
}
})
})
} catch (error) {
console.log(error);
}
}
const fileDownload = async (req, res) => {
const {dir: directory, file: fileName} = req.params
const filePath = path.join(homeDir + '/uploads/' + directory + '/' + fileName)
fs.access(filePath, fs.constants.F_OK, err => {
//check that we can access the file
console.log(`${filePath} ${err ? "does not exist" : "exists"}`);
});
res.download(filePath)
res.end()
}
I even check the file with fs.access and it returns true (it prints {filepath} exists), but the file is not served at all.
Any kind of help is much appreciated!
EDIT:
Decided to work on my front end a bit to cool off, came back and immidiatelly noticed res.end() just below send file, which ends the transmission. Removed it and it works like a charm!
Related
I am trying to write an application which functionality includes storing files in MongoDB. I succeeded in uploading files there, with the GridFS library, but then I failed many times trying to get access to the data. I constantly get a response with internal server error while loading files metadata with this request:
router.get('/uploads', async (req,res) => {
try {
gfs.files.find().toArray( (err, files) => {
if(!files || files.length === 0) {
return res.status(404).json({message: 'No files exisits'})
}
})
res.status(200).json(files);
} catch (error) {
return res.status(500).json({ message: "Could not find files, please try again" });
}})
content-type: application/json; charset=utf-8
The other request for downloading a certain file data ruins my whole backend and I get this error:
Proxy error: Could not proxy request /api/user/getuser from localhost:3000 to http://localhost:4000/ (ECONNREFUSED).
After that none of my requests work properly on any page.
And that's a nodejs code of that request:
router.get('/uploads/:filename', async (req,res) => {
try {
gfs.files.findOne({filename: req.params.filename}, (err, file) => {
if(!file || file.length === 0) {
return res.status(404).json({message: 'No file exisits'})
}
})
res.status(200).json(file);
} catch (error) {
return res.status(500).json({ message: "Could not find files, please try again" });
}})
GridFs configurations are next:
const conn = mongoose.createConnection(config.get('mongoURI'));
conn.once('open', () => {
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('uploads');
})
const storage = new GridFsStorage({
url: config.get('mongoURI'),
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(15, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
I assume that I missed something important in documentation, and I'm not even trying to download a whole image, I am stuck. Useful advices would be highly appreciated!
I found the issue which caused an error! While emulating my request I got this error:
[0] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Therefore the problem was in that part of my code:
res.status(200).json(files);
Nodejs does not allow to set the header of status after the actual body of request was sent.
So all the fixes I had to do were:
res.status(200).json(files) to --> res.json(files);
I hope the solution would be useful for someone.
I just deployed a small weather app project with Heroku and I am getting an internal server error when user enters an invalid city or zip code. I added a .catch in my route to render an error page if this happens, and it works exactly as intended in my local version, but not on the deployed version. Does anyone know why this might be? I am using .ejs templates to render my pages.
app.get("/results_city", (req, res) => {
let query = req.query.search;
console.log("Search params:", query);
let weatherApiKey = process.env.WEATHER_API_KEY;
let weatherUrl =
"https://api.openweathermap.org/data/2.5/weather?q=" +
query +
"&appid=" +
weatherApiKey;
rp(weatherUrl)
.then((body) => {
let data = JSON.parse(body);
res.render("results", { data: data });
console.log(data);
})
.catch(err => {
if (err) {
res.render("Error")
return;
}
console.log(err);
});
});
Hello everyone I'm trying to create an app with a backend where the user will be able to upload a profile pic. I'm using nodejs for the back with the framework Expressjs.
However, when I try to upload an image to my server from my react-native app nothing gets saved into my images folder.
I'm on iOS right now, I don't know if it changes anything.
When I tried to do the same but without react-native directly sending POST request using Postman I was able to do so.
I don't really know why I thought it would be extension name or something but it does not change anything.
Here is my backend code first :
I'm using Multer for the upload
const storage = multer.diskStorage({
destination : function(req, file, cb ){
cb(null,'./images/');
},
filename : function(req,file,cb){
cb(null, Date.now() + file.originalname);
}
})
const upload = multer({ storage : storage,
//filer only valide file == image
fileFilter: function(req,file,cb){
let ext = path.extname(file.originalname);
if(ext != '.png' && ext != '.jpg' && ext !='jpeg'){
return cb('Only images are allowed ')
}
cb(null, true)
},
limits:{fieldSize: 25*1024*1024}
})
// route for photo TEST
router.post('/upload',upload.single('photo'), (req,res)=> {
console.log('file',req.files);
//console.log('body', req.body);
res.status(200).json({
message:'success!',
});
});
And now this is what I do on my react-native app
const createFormData = (photo, body) =>{
const data = new FormData();
data.append('photo', {
name:photo.fileName,
type:photo.type,
uri :
Platform.OS === 'android' ? photo.uri : photo.uri.replace('file://', ''), // to be sure it works with android
});
Object.keys(body).forEach(key => {
data.append(key, body[key]);
});
return data;
handleUploadPhoto = () =>{
fetch('http://localhost:5050/api/new/upload',{
method: 'POST',
body: createFormData(this.state.dataPhoto,{userId : 'test'}),
})
.then(response => response.json())
.then(response => {
console.log('upload succes', response);
alert('Photo updated succesfully!')
})
.catch(error => {
console.log('upload failed', error);
alert('Upload is not possible right now!');
})
};
I do get the alert("Photo updated succesfully on my screen" so I guess it works on the front but not on the back...
I load the image using react-native-image-picker
I don't get any error message but no files are saved into my images folder.
Thanks in advance for any help
Are you not seeing anythign related to console.log('file', req.files) which you printed ?
Verify when you upload , you are getting the file + the uploaded file related ojbects in the node console.
Enable the console body log and also view it console.log('body', req.body)
Im passing a file to node.js with AJAX. the file is passed as a Base64 string and I pass it using multipart/form-data. The AJAX part work flawlessly, but I need to have said string stored on a variable in server side i.e. in Node.js. Now, on PHP this would be super easy:
$someVar = $_POST["myBase64EncodedFile"];
How can I achieve exactly that but with Node.js? I have to use Node.js and I dont want the file to be saved in some temp folder, I just need the string on a variabe. Any ideas? Thanks.
use formidable modules.
in express , you can ues it like this:
var formidable = require('formidable');
const form = new formidable.IncomingForm();
function handlerFormByEvent(req, res, next) {
form
.parse(req)
.on('fileBegin', (name, file) => {
console.time('start');
console.log('name', name);
file.path = `uploads/${file.name}`;
})
.on('progress', (accepted, total) => {
console.log(`accept:%d,total:%d`, accepted, total);
})
.on('field', (name, field) => {
console.log('field', name, field);
})
.on('file', (name, file) => {
// handle file
console.log('name', name);
console.log(file.toJSON());
})
.on('aborted', error => {
let message = error.message;
res.render('error', { message, error });
})
.on('error', err => {
console.error('Error', err);
let message = err.message;
res.status(err.status || 500);
res.render('error', { message, error: err });
})
.on('end', () => {
res.end('ok');
});
}
I'm creating an api using Sails JS v1.0.0
I have an action to upload an image to the server and it's working great but the problem I'm having is that I want to save the image URL to the user uploaded the image. It's the user profile image.
The code seems to work fine but I get an error in the terminal after uploading the image. I guess it has something with the callbacks.
Here is my controller:
let fs = require('fs');
module.exports = {
upload : async function(req, res) {
req.file('image').upload({ dirname : process.cwd() + '/assets/images/profile' }, function(err, uploadedImage) {
if (err) return res.negotiate(err);
let filename = uploadedImage[0].fd.substring(uploadedImage[0].fd.lastIndexOf('/')+1);
let uploadLocation = process.cwd() +'/assets/images/uploads/' + filename;
let tempLocation = process.cwd() + '/.tmp/public/images/uploads/' + filename;
fs.createReadStream(uploadLocation).pipe(fs.createWriteStream(tempLocation));
res.json({ files : uploadedImage[0].fd.split('assets/')[1] })
})
}
};
About the read stream to the .tmp folder, I wrote it to make the image available the moment it gets uploaded.
I tried to query for the user right before the
res.json({ files : uploadedImage[0].fd.split('assets/')[1] })
line, but it gives me an error in the terminal.
What's the best way to implement this code?
User.update({ id : req.body.id }).set({ image : uploadedImage[0].fd.split('images/')[1] });
You are uploading images to '/assets/images/profile' and trying to fetch it from '/assets/images/uploads/'. Also wrong path in tempLocation variable too. Change your code to following and it will hopefully start working
upload : async function(req, res) {
req.file('image').upload({ dirname : process.cwd() + '/assets/images/profile' },
async function(err, uploadedImage) {
if (err) return res.negotiate(err);
let filename = uploadedImage[0].fd.substring(uploadedImage[0].fd.lastIndexOf('/')+1);
let uploadLocation = process.cwd() +'/assets/images/profile/' + filename;
let tempLocation = process.cwd() + '/.tmp/public/images/profile/' + filename;
fs.createReadStream(uploadLocation).pipe(fs.createWriteStream(tempLocation));
await User.update({ id : req.body.id }).set({ image : uploadedImage[0].fd.split('images/')[1] });
res.json({ files : uploadedImage[0].fd.split('assets/')[1] })
})
},