I am trying to upload some files, through an HTML form, in my local drive, which I was able to complete successfully. However, when attempting to play the mp3 uploaded file, by accessing the url of the "mp3 player", the server redirects me to the uploading page and I can not understand why this happens. I am quite a begginer, when it comes to node.js and I do not really know that much about JavaScript, as I have little experience with it. You can check the code below:
var http = require('http'),
fs = require('fs'),
filePath = './test.mp3',
stat = fs.statSync(filePath);
var formidable = require('formidable');
http.createServer(function(request, response) {
//fs.createReadStream(filePath).pipe(response);
if(request.url == '/playUploadedFile') {
fs.createReadStream(filePath).pipe(response);
response.writeHead(200, {
'Content-Type': 'audio/mpeg',
'Content-Length': stat.size,
});
}
if (request.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(request, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = __dirname + '/' + files.filetoupload.name;
filePath = newpath;
console.log(filePath);
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
response.write('File uploaded and moved!');
//request.url = '/playUploadedFile';
response.end();
});
});
} else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
response.write('<input type="file" name="filetoupload"><br>');
response.write('<input type="submit">');
response.write('</form>');
return response.end();
}
}).listen(8080)
In order to serve static file you have to declare your upload path to static. This way node understands the files within the specified path needs to be served exactly the way it is. The easiest way to do this is to use express https://expressjs.com/en/starter/static-files.html. But you can also use node-static https://www.npmjs.com/package/node-static package as well.
Related
There are many question similar to my question on stack overflow. However not solved my problem.
I am getting this error on Ubuntu 18.04:
Error: EXDEV: cross-device link not permitted, rename
'/tmp/upload_df97d265c452c510805679f968bb4c17' -> '/home/haider/workspaceNode/DSC_0076.JPG'
I Tried This code
var http = require('http');
var formidable = require('formidable');
var fs = require('fs');
http.createServer(function (req, res) {
if (req.url == '/fileupload') {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = '/home/haider/workspaceNode/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(8081);
I suppose that Node's fs.rename cannot rename across filesystems (that is, limited to link/unlink within one filesystem).
Wherever your /home is, it's a safe bet to suppose that /tmp is a tmpfs filesystem actually residing in memory. (You can check in the output of mount.)
So, to move a file, you have to fs.copyFile your data to the destination, then fs.unlink the original downloaded file.
You can upload a temporary file into a device with script's file system:
var form = new formidable.IncomingForm({
uploadDir: __dirname + '/tmp', // don't forget the __dirname here
keepExtensions: true
});
from here https://stackoverflow.com/a/14061432/7773566
I am trying to setup a file API in my node.js application. My goal is to be able to write the file stream directly to gridfs, without needing to store the file to disk initially. It seems like my create code is working. I am able to save a file upload to gridfs. The problem is reading the file. When I try to download a saved file via a web browser window, I see that the file contents are wrapped with something like the following:
------WebKitFormBoundarye38W9pfG1wiA100l
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: text/javascript
***File contents here***
------WebKitFormBoundarye38W9pfG1wiA100l--
So my question is what do I need to do to strip the boundary information from the file stream before saving it to gridfs? Here's the code i'm working with:
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
// I think this works. I see the file record in fs.files
exports.create = function(req, res) {
var fileId = new mongoose.Types.ObjectId();
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: req.query.name,
mode: 'w',
content_type: req.query.type,
metadata: {
uploadedBy: req.user._id,
}
});
writeStream.on('finish', function() {
return res.status(200).send({
message: fileId.toString()
});
});
req.pipe(writeStream);
};
// File data is returned, but it's wrapped with
// WebKitFormBoundary and has headers.
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
// With this commented out, my browser will prompt
// me to download the raw file where I can see the
// webkit boundary and request headers
//res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
// I also tried this way:
//_id: file._id
});
readstream.pipe(res);
});
};
By the way, i'm not currently using any middleware for these routes, but am open to doing so. I just didn't want the file to hit the disk prior to being sent to gridfs.
Edit:
Per #fardjad, I added the node-multiparty module for multipart/form-data parsing and it kind of worked. But when I download an uploaded file and compare with an original (as text), there are lots of differences in the encoding, and the downloaded file won't open. Here's my latest attempt.
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var multiparty = require('multiparty');
var Grid = require('gridfs-stream');
Grid.mongo = mongoose.mongo;
var gfs = new Grid(mongoose.connection.db);
exports.create = function(req, res) {
var form = new multiparty.Form();
var fileId = new mongoose.Types.ObjectId();
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
form.on('part', function(part) {
if (part.filename) {
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: part.filename,
mode: 'w',
content_type: part.headers['content-type'],
metadata: {
uploadedBy: req.user._id,
}
})
part.pipe(writeStream);
}
});
// Close emitted after form parsed
form.on('close', function() {
return res.status(200).send({
message: fileId.toString()
});
});
// Parse req
form.parse(req);
};
exports.read = function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
res.writeHead(200, { 'Content-Type': file.contentType });
var readstream = gfs.createReadStream({
_id: req.params.id
});
readstream.pipe(res);
});
};
Final Edit:
Here's a simple implementation that I copied from another developer and modified. This is working for me: (I'm still trying to figure out why it won't work in my original express app. Something seems to be interfering)
https://gist.github.com/pos1tron/094ac862c9d116096572
var Busboy = require('busboy'); // 0.2.9
var express = require('express'); // 4.12.3
var mongo = require('mongodb'); // 2.0.31
var Grid = require('gridfs-stream'); // 1.1.1"
var app = express();
var server = app.listen(9002);
var db = new mongo.Db('test', new mongo.Server('127.0.0.1', 27017));
var gfs;
db.open(function(err, db) {
if (err) throw err;
gfs = Grid(db, mongo);
});
app.post('/file', function(req, res) {
var busboy = new Busboy({ headers : req.headers });
var fileId = new mongo.ObjectId();
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
console.log('got file', filename, mimetype, encoding);
var writeStream = gfs.createWriteStream({
_id: fileId,
filename: filename,
mode: 'w',
content_type: mimetype,
});
file.pipe(writeStream);
}).on('finish', function() {
// show a link to the uploaded file
res.writeHead(200, {'content-type': 'text/html'});
res.end('download file');
});
req.pipe(busboy);
});
app.get('/', function(req, res) {
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/file" enctype="multipart/form-data" method="post">'+
'<input type="file" name="file"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
});
app.get('/file/:id', function(req, res) {
gfs.findOne({ _id: req.params.id }, function (err, file) {
if (err) return res.status(400).send(err);
if (!file) return res.status(404).send('');
res.set('Content-Type', file.contentType);
res.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
var readstream = gfs.createReadStream({
_id: file._id
});
readstream.on("error", function(err) {
console.log("Got error while processing stream " + err.message);
res.end();
});
readstream.pipe(res);
});
});
See my comment on the issue you created on github. I had the same problem but I managed to debug the issue. I narrowed it down to where i was confident that the problem was a piece of express middleware modified the request. I disabled my middleware one by one until i found the unlikely culprit: connect-livereload
I commented out app.use(require('connect-livereload')()); and the problem went away.
I believe it was injecting the livereload script into the response (a binary image file).
Looks like the file has been uploaded through an HTML form, in that case you need to decode the multipart/form-data encoded data, re-assemble the parts if needed and save the file to GridFS. For parsing, you can use something like node-multiparty.
I have made a server using javascript and Node.js that shows a JSON file in my browser.
However, I would like to call the site http://localhost:8888/Test.json without an extension.
For example just: http://localhost:8888/Test
Here is my server code:
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs")
port = process.argv[2] || 8888;
file = (__dirname + '/Test.json');
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname, filename = path.join(process.cwd(), uri);
var contentTypesByExtension = {
'.html': "text/html",
'.css': "text/css",
'.js': "text/javascript",
'.json': "application/json" //Edited due to answer - Still no success :(
};
path.exists(filename, function(exists) {
if(!exists) {
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("404 Not Found\n");
res.end();
return;
}
fs.readFile(file, 'utf8', function (err, file) {
if (err) {
console.log('Error: ' + err);
return;
}
file = JSON.parse(file);
console.dir(file);
var headers = {};
var contentType = contentTypesByExtension[path.extname(file)];
if (contentType) headers["Content-Type"] = contentType;
res.writeHead(200, headers);
res.write(JSON.stringify(file, 0 ,3));
res.write
res.end();
});
});
}).listen(parseInt(port, 10));
console.log("JSON parsing rest server running at\n => http://localhost:" +
port + "/\nPress CTRL + C to exit and leave");
How can I do that?
Should I use routes/express?
Does someone have any suggestions?
Thank you in advance!
Cheers, Vlad
Your problem is probably due to the content type. Having the extension .json is probably triggering your browser to consume it as application/json. So if you remove the extension you need to add the proper Content-Type.
Given that you are already playing around with content types, can't you just add it here, and make sure you write the type for jsons as well?
var contentTypesByExtension = {
'.html': "text/html",
'.css': "text/css",
'.js': "text/javascript",
'.json': "application/json" // <---
};
I've just used the sledgehammer method now with commenting this code fragment out:
if(!exists) {
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("404 Not Found\n");
res.end();
return;
}
Now it works to call just: http://localhost:8888/Test
Cheers, Vlad
So I have been wondering how to save an image to node.js server without the use of express.(just learning node and want to make everything myself to learn node better, without express).
So far I have a form with the image as only input which I send with a post request. This is what I have so far on my server, which does not log anything.
if(req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
res.writeHead(200, {'Content-Type': 'image/jpg; charset=utf8'});
req.on('data', function (chunk) {
fs.writeFile(__dirname + "/uploads/dada.jpg", chunk, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
}
}
This is my form:
<form method="post" action="/upload" enctype="multipart/form-data">
EDIT: I fixed most of the problems, but the file is only saved as an image, but cannot be viewed like one. (Something is wrong with the content-type I guess, but don't know how to fix it)
Here is fiddle of my whole app. I know I need to separate it in different modules, but I will do that later
I completely forgot about this old question but now that I see it has quite some views, here is the solution I found:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs'),
GUID = require('GUID'),
formidable = require('formidable'),
util = require('util');
var app = http.createServer(function (req, res) {
if (req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function (e) {
console.log('Problem with request: ' + e.message);
});
var fileDirectory = __dirname + '/db/',
form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir =fileDirectory;
form.parse(req, function (err, fields, files) {
if (err) throw (err);
var pic = JSON.stringify(util.inspect(files)),
upIndx = pic.indexOf('db'),
path = pic.slice(upIndx + 6, upIndx + 42);
res.writeHead(200, {
'Content-Type': 'text/html'
});
fs.readFile('views/index.html', function (err, page) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.write(page);
res.write('<div>Download Link: </div><div>' + fileDirectory + path + '</div>');
res.end();
});
});
}
} else {
//not important for question, handle other request
}
});
app.listen(port);
console.log('Server running on port: ' + port)
I am with a problem over here, I am using node.js framework to handle the requests to my index.html.
The index.html file has some images, but its not appearing for my users!
I am reading both files, index.html and the .png .
Can you guys help me?
Here is my server.js:
var app = require('http').createServer(handler)
var io = require('socket.io').listen(app)
var fs = require('fs')
app.listen(4000);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
return res.end('Error loading index.html');
}
res.end(data);
});
fs.readFile(__dirname + '/blackq.png', function (err, data) {
if (err) {
return res.end('Error loading index.html');
}
res.end(data);
});
}
THanks alot in advance!
A quick solution just for proof of concept could go like this:
In your html file, make sure you have the img tab done right.
<img src="/your_image.jpg" alt="your_image" style="width:304px;height:228px;">
In your node.js server file, adding
if (req.url == "/index.html") {
//res.end your html file
return;
}
//to display image
if (req.url == "/your_image.jpg") {
var img = fs.readFileSync('./your_image.jpg');
res.writeHead(200, {'Content-Type': 'image/jpg' });
res.end(img, 'binary');
return;
}