I am now using Express4 and want to upload files to the file system of the server. (for example, save the files in the public/files folder.)
There are several questions about how to user formidable or busboy to parse the request like this example:
var formidable = require('formidable'),
http = require('http'),
util = require('util');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(util.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(
'<form action="/upload" enctype="multipart/form-data" method="post">'+
'<input type="text" name="title"><br>'+
'<input type="file" name="upload" multiple="multiple"><br>'+
'<input type="submit" value="Upload">'+
'</form>'
);
}).listen(8080);
Such middleware could parse req to get the metadata, like the file path, name, size, etc. However, if I want to POST different files to different endpoints, I would like to use angularjs controller and service structure to process the uploading.
Wondering how can I get file path, name, etc to controller/service and post them to the backend. Then I can use the following codes to upload files.
api.post(url, function(req, res) {
var fs = require('fs');
//req.body.path: path of file, like, C:\\user\John\.....
//req.body.filename: name of file, like images.jpg
fs.readFile(req.body.path, function(err, data){
var uploadToPath = './public/files/' + req.body.filename;
fs.writeFile(uploadToPath, data, function(err){
if(err) {
res.send(err);
return;
}
});
});
});
I am also referring this solution, but it can only get the info like file size, but not the very important file path.
pls advise, many thanks.
For the node/express side:
Check out https://github.com/expressjs/multer
For the angular side:
Check out https://github.com/danialfarid/ng-file-upload
It makes uploading and saving single or multiple files super easy. They have an option in there for directory to automatically save to.
https://github.com/expressjs/multer#multeropts
File path will be your file path in express. So if its in a route the path will be that directory. Use a node core module path = require ('path') that will expose __dirname that'll let you change the path using core modules where needed. Path is relative to your system you won't get the clients path with the post request.
EDIT:
After reading the standard https://w3c.github.io/FileAPI/#attributes-blob
You can not get the file path. That's logical since that could be a potential privacy encroachment. If you're developing on node WebKit on the other hand your application would have access to users file system through the use of node core module path.
Related
I found a example from expressjs:
res.download('/report-12345.pdf');
to prompt the user for download. But i pass a url as parameter. It not working.
res.download just accepts path to filesystem in local.
For your requirement you can do one of below:
1) use res.redirect({URL})
2) get that file from URL and then send file to client like :
app.get('/', function(req, res){
http.get(URL, function(file) {
file.pipe(res);
});
});
This worked for me
const https = require("https");
const fileName = "the file name" + ".mp4";
https.get(url, function (file) {
res.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
res.set('Content-Type', 'video/mp4');
file.pipe(res);
});
Here select the Content-Type for you file
Here's a list of mostly all content type
In the fileName add the file extension of your file i.e. ( .jpg , .png , .txt)
The first parameter to the res.download() method is the absolute path to the file on the filesystem, not a network URL. So if you say res.download('/report-12345.pdf'); you are trying to download the report-12345.pdf file from the root folder of your filesystem.
I got this third party lib which generates a screenshot.
I want to save this on my server. I'm using Axios.It's probably something with blobs, arraybuffers etc?
How do I send it?
Axios.post('/api/saveimage', { ??? })
Using NodeJs express on backend. How do I save this to a physical image file?
Well at the frontend you need to send it like this:
let formData = new FormData()
formData.append("image", file)
axios.post("/api/saveimage",formData)
At the first step you create a FormData, then you append the file. In this case i named the file image. Now lets go to the next step. You will need multer on your nodejs side.
npm i multer
The first think you need to do, is to create an middleware:
const multer = require("multer");
const whitelist = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
const storeImages = multer.diskStorage({
destination: async function (req, file, cb) {
if (!whitelist.some((type) => type === file.mimetype)) {
return cb(new Error("File is not allowed"), "/");
}
cb(null, "your/destination/path");
},
filename(req, file, cb) {
let [name] = file.originalname.split(".");
cb(null, name + ".png");
},
});
exports.uploadImageStorage = multer({
storage: storeImages,
});
Here watch out: Your destination path should exist. Also dont forget an extension for your file in this case .png
Now you create your route:
const { uploadImageStorage } = require("../yourstorage")
app.post("/api/saveimage", uploadImageStorage.single("image"), (req, res) => {
let file = req.file
let path = file.path
})
Here you need to know at uploadImageStorage.single("image") i used image like i used it in formData.append("image", file) they need to be the same.
Now you can save the path of your file into a database. You can also transform your image with sharp if you want
From my experience if you have folder called static and you have a image inside of it like photo.png you usually get the photo with localhost:3000/photo.png and not with localhost:3000/static/photo.png
You will need to remove static from your path if you have this setup. Otherwise if you try to display the image on the frontend you wont see it.
I created localhost/server on node js, and my pictures/img tag doesn't work
<div class="text-center">
<img alt = "Bulb" src="pic_bulboff.gif" class="rounded" alt="bulboff">
</div>
but the problem is that they show up when I open them in a regular browser without the server
const http = require('http')
const fs = require('fs')
const port = 3000
const server = http.createServer(function(req, res){
res.writeHead(200, { 'Content-Type': 'text/html'})
fs.readFile('index.html', function(error, data) {
if(error) {
res.writeHead(404)
res.write('Error: File not Found')
} else {
res.write(data)
}
res.end();
})
})
above is the node server.
is there a problem that I can't really see?
Thanks!!!
By default a nodejs http server does not serve ANY files at all. You've created an http server that serves index.html for ALL incoming requests. So, a browser makes a request from your web server and you send it the HTML content from index.html.
Then, the browser parses that HTML and sees an <img> tag with a src attribute of "pic_bulboff.gif" so the browser then sends a request to your web server asking it for the content for /pick_bulboff.gif. But, you web server just responds to that request by sending index.html. That obviously doesn't work. You need your web server to know the difference between different path requests so it will server index.html when the browser is requesting /, but will serve that image when the browser is requesting /pick_bulboff.gif.
While most people will use a simple web framework that has the serving of static files as a built-in feature (like the Express framework), you can do it manually if you want:
const http = require('http');
const fs = require('fs');
const port = 3000;
function sendFile(fname, contentType) {
res.writeHead(200, { 'Content-Type': contentType});
fs.readFile(fname, function(error, data) {
if(error) {
res.writeHead(404);
res.write('Error: File not Found');
} else {
res.write(data);
}
res.end();
}
}
const server = http.createServer(function(req, res){
if (req.url === "/") {
sendFile('index.html', 'text/html');
} else if (req.url === '/pick_bulboff.gif') {
sendFile('pick_bulboff.gif', 'image/gif');
} else {
res.writeHead(404);
res.end('Error: Unsupported path');
}
});
server.listen(port);
In a more typical implementation, you would put all static files in one directory hierarchy that was separate from your code and you would use functionality similar to express.static() in the Express framework to serve any file in that static files directory that matches an incoming request so you don't have to create a custom route for every single static file you're using in your project.
I have a very simple web server like this:
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
fs.readFile('./index.html', 'utf-8', function (err, content) {
if (err) {
res.end('something went wrong.');
return;
}
res.end(content);
});
}).listen(8080);
console.log("Server running on port 8080.")
This renders my index.html without any issues, but if I try to reference another file in my index.html via a script tag for instance, the site just gets stuck, unable to find the file which exists in the server directory.
How can I make those files available to my index.html file?
Please keep in mind that I realize this can be done much more easily with Express but I do not wish to use Express. I am trying to learn how things work behind the scene. Thanks in advance.
You need to make the directory visible to public. Its is recommend to use framework while developing the Node.js application.
Here is the code below to server file without framework.
var basePath = __dirname;
var http = require('http');
var fs = require('fs');
var path = require('path');
http.createServer(function(req, res) {
var stream = fs.createReadStream(path.join(basePath, req.url));
stream.on('error', function() {
res.writeHead(404);
res.end();
});
stream.pipe(res);
}).listen(9999);
Refer : Node itself can serve static files without express or any other module..?
So I have craeted a node.js server with two routes. I use the fs to get the html files from the views folder and then append them to the page. In those html files I have a normal link to the css file, which does not seem to work. Here is my node.js app:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs');
var app = http.createServer( function(req, res) {
if (req.url === '/home') {
fs.readFile('views/index.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
else if (req.url === '/about') {
fs.readFile('views/about.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
else {
res.writeHead(301,
{Location: '/home'}
);
res.end();
}
});
app.listen(port);
console.log('Server running on port: ' + port)
In the html files I have:
<link rel="stylesheet" type="text/css" href="./styles/styles.css">
It does not work. In chrome's console I get "Resource interpreted as Stylesheet but transferred with MIME type text/html. "
You defined 2 routes: /home and /about. You also defined that anything apart from these two routes should default to an HTTP redirect to the /home route, and this is what causes the problem.
When the browser encounters the link to the css file, it requests the following URL: /styles/styles.css. the server receives this URL and since it doesn't match the two defined routes it will go into the else statement which will send a redirect to /home, so your browser, asking for a css file, will only receive the html page located in /home.
To fix this, you might need to add a new rule for your css file:
else if (req.url === '/styles/styles.css') {
fs.readFile('styles/styles.css', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/css'});
res.write(page);
res.end();
});
}
Of course, if you have more css files you need to manage a specific folder instead of files. I suppose you're doing this to learn Node, because if you don't you might want to use express which is a Node ready to use web server that will save you lot of time.
When the client (the browser) asks the server for /styles/styles.css the server responds with 301 Moved Permanently and Location: '/home'.
The browser then asks for /home and gets an HTML document, which is not a stylesheet.
You have to give the browser the stylesheet when it asks for it.
static assets (as in your stylesheets) wont be served automatically. So what happens is that it falls through and lands at the 301 redirect to /home, where you serve text/html.
If you want to serve css that way, add a rule req.url==="/styles/styles.css"
Generally, I would recommend using a routing lib like express or koa. Or as minimum, connect. They make it easy to hook in features called middleware and enable you to make everything in a directory (like /public) serve static content with one rule.