I'm using express.js's app.use(express.static(...)) to serve my files. I'd like to configure some restricted files and make routings (such as redirecting requests ending in .png to a specific folder). Is this possible?
You can't get what you need from the express.static middleware, however most of these are easy to implement.
To setup restricted files, simply put a middleware above your express.static middleware in the gist of:
app.use(function(req,res,next){
if (req.url == "/path/to/bad/file") res.send(403)
else next();
})
to setup redirection (using the same type of middleware), you have two options either perform res.redirect("real path") or send the file yourself using res.sendFile("path"), which is more or less what express.static does.
Related
I'm learning Node.js with Express to get a little server running for studying. I'm getting response code 404 for all requests to files linked in my index.html file (e.g. the .css, .js, and image files).
The code I used to send index.html:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide/index.html"));
})
If I change the path to the whole folder instead:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide"));
})
I get in my browser the path from my hard drive to the folder, but I still can't view the files that way.
The clientSide folder contains index.html, app.js, style.css, and 2 or 3 images, all in the same folder. I can't view any of them.
I changed the filenames and folder name, and checked for capitalization to no avail.
SOLVED
I was using app.use(express.static(path.join(__dirname, "static/")));
With app = express();
That does not work, but using routes.use instead of app.use, while routes = express.Router();, is what solves that
The end
In your first code snippet, when you write:
routes.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/clientSide/index.html"));
})
You defined a new middleware function for requests to route /; that's what routes.get('/', ...) does. Assuming your server is running on port 3000, route / maps to http://127.0.0.1:3000/. For exactly that URL, and no other, Express executes your provided function, which replies with the the file clientSide/index.html. Thus, when your browser requests http://127.0.0.1:3000/, Express responds correctly.
But you've said nothing about the other files, such as http://127.0.0.1:3000/style.css, which would be route /style.css. You haven't defined any middleware for that route. So Express, not knowing what to do, by default responds with 404 and an error message. Thus, when your browser tries to load http://127.0.0.1:3000/style.css while fetching the resources referenced in index.html, the stylesheet fails to load.
Your second code snippet doesn't fix anything. It really makes things worse, because res.sendFile() can't send folders (how would that even work?) and that generates errors. You still haven't defined routes other than /, and now all your files are inaccessible.
To actually solve the problem, you could, theoretically, tediously define a route for every file, or more cleverly define one route with a route parameter. But serving a static folder with Express is a solved problem. You can simply offload the work to express.static by replacing all your code with:
routes.use(express.static(path.join(__dirname, "clientSide/")));
To go even further, you don't need Express or Node.js for a static file server. Try nginx. And for simple webpages, you don't need a server at all; just double-click index.html and let your browser open it.
I am creating a very simple project that uses JWT. I am serving everything via express, I do not have a frontend and backend. What I want to do is serve SPECIFIC html files based on the user's authorization (serving on https://localhost:3000 entry point server.js)
People keep recommending to use (server.js):
app.use(express.static('static'))
but this of course does not work as I can access ANY of those files by going to https://localhost:3000/whatever.i.want.
I have also tried (server.js):
app.use( '/secret' , authMiddleware, function(req,res){
if(auth){
res.sendFile(__dirname + '/static/secret.html')
}
});
but gives 404s on my stylesheet and script, as well as some weird MIME type error
Refused to execute https://localhost:3000/script.js as script because "X-Content-Type: nosniff" was given and its Content-Type is not a script MIME type.
It works if I add:
app.get( '/styles.css' , function(req,res){
res.sendFile(__dirname + '/static/styles.css')
});
app.get( '/script.js' , function(req,res){
res.sendFile(__dirname + '/static/script.js')
});
But do I really have to do this for every single stylesheet and script I use? There has to be a better way!!!
1.) What is the best way that people do this? Specifically, is it possible to create authorized web-apps without using a frontend and serving all your static files from the backend?
2.) Is it necessary that your static directory is publicly accessible? Meaning you can only cast authorization constraints on certain endpoints, then use a script file that calls those endpoints? Which would still allow you to view the base HTML, just not any results of the API calls. Which in effect works but is gross.
File system
server.js
/static
/blah.html
/secret.html
/secret.css
/secret.js
If you want to selectively serve assets from the express server, you could do something like this:
let secrets = ['secrets.html', 'my_diary.html']
app.use((req, res, next) => {
let shouldBeAuthorised = secrets.some(s => req.url.includes(s))
if (shouldBeAuthorized)
// check they are authorized to be served this content
else
// just serve the content, carry on... no need to worry
})
app.use(express.static('static'))
My use of req.url.includes is very shaky, and with a more complicated list of files, could result in you requiring authorization for files that aren't explicitly in the blacklist... but the basic structure of the above code should achieve what you're looking to achieve.
You can solve this by having a folder called public, which you can put all the css, js in that folder. And use static middleware to serve the public folder
app.use(express.static('public'))
Then there is another folder called secret, which you will build routes, validate JWT token and serving html files based on user permission
How to send images to a page on my node.js server along with the html? How do I use express static to send images? (Need an example here)
Server side ->
app.get('/', function (req, res) {
res.sendFile(__dirname + '/login.html');
});
app.post('/m', function (req, res) {
res.sendFile(__dirname + '/m/a.png');
res.sendFile(__dirname + '/m/b.png');
res.sendFile(__dirname + '/m/c.png')
res.sendFile(__dirname + '/m/d.html');
});
In a web server, you don't just send multiple images to a page. Instead, the browser requests the page HTML, parses it, finds <img> tags in the HTML and then requests each of those images separately and your web server responds to each separate image request by sending the requested image.
If you put all your images in a common folder, then you can use express.static() to handle all the image requests with one line of code. For example a line of code like this:
app.use("/image", express.static(path.join(__dirname, "public")));
Would serve all image requests for URLs like this:
/image/a.png
/image/b.png
by finding the matching a.png and b.png in the "public" sub-directory below __dirname (which is the directory of the script). You can read more about express.static() here. You can obviously play with the path of the URL you want to use and the path where the images are found. The two just have to work together so that express.static() can find the right image in the corresponding place on the server hard drive where you've put it.
There is often some confusion in understanding how the separate path components in app.use() and express.static() work together. In the above example, the "/image" will be part of the request URL and this app.use("/image", ...) tells express that you want to apply this particular middleware to any request path that starts with /image.
Then path.join(__dirname, "public") is telling express.static() to take the rest of the URL path after the /image and look for that in the subfolder public below the directory __dirname. So, if the browser requests /image/a.png, the app.use() statement will trigger because /image matches that URL and then express.static() will try to find the remaining part of the path a.png in the directory you told it to look in.
On your server hard disk, this would look like this:
/myproject/
app.js
login.html
/public
a.png
b.png
I've shown login.html in the same directory as app.js only because that's how you're code seems to be currently written. I personally don't put any public files in the same directory as my server scripts because I want it to be easy to not make mistakes and accidentally expose my server files to the public.
I would more typically do it like this:
/myproject/
app.js
/public
login.html
a.png
b.png
app.use("/image", express.static(path.join(__dirname, "public")));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, "public", "login.html"));
});
Or, just let express.static() serve the login.html file too.
I would like to show a custom 404 page (containing html, css, img, and ico). I know my 404 folder works when I replace the first public static homepage. However, I believe I am either not using routes the right way or it is not possible to set up two static folders.
I do not want to use template view engines at all. I want everything to be rendered on the frontend.
My project looks as follows:
404
--index.html
--error.css
--404.jpg
bin
--server.js
public
--index.html
routes
--index.js
package.json
app.js
app.js
...
var index = require(./routes/index); //works
...
app.use(favicon(__dirname + '/public/content/images/logo.ico'));
app.use(logger('dev'));
app.use(jsonParser);
app.use(urlencodedParser);
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public'))); //love it
app.use('/', index); //this is fine
...
index.js
var express = require('express');
const path = require('path');
var router = express.Router();
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
router.use('/', express.static(path.join(__dirname, './404'))); // HALP!
module.exports = router;
I've played around with the directory (trying to use '404' vs './404'). I am testing this by entering "localhost:3000/error". So if my path is '/error', it should still use the parent path: '/'. The documentation states that as long as my route is placed last, it should still work. I tested it without express.static and used an anon function that prints error on console.
Is it impossible to use express.static() twice?
Moving some of my comments into an answer since this led to your solution.
For Express.js 4.x, is it possible to use express.static twice?
Yes, you can use express.static() as many times as you want. It is middleware and, if it does not find a file matching the request, it just calls next() and allows the middleware chain to continue. So, you can have as many of them as you want and they will each get to search for a matching file in the order you register them.
I would like to show a custom 404 page (containing html, css, img, and ico). I know my 404 folder works when I replace the first public static homepage. However, I believe I am either not using routes the right way or it is not possible to set up two static folders.
You are mistakenly trying to use express.static() to implement a custom 404 page. That is not what it does. The usual way to implement a custom 404 page is with the last middleware handler in the chain. When that gets hit, nothing else has found a match for the current request, therefore you send your custom 404 page.
That typically looks like this:
app.use(function(req, res, next) {
res.status(404).sendFile(localPathToYour404Page);
});
See the "How do I handle 404 responses" section of this Express starter FAQ.
And, here's an article on custom error pages that shows some other examples.
https://github.com/jekku/users/blob/master/server.js#L41
Here's how I route my static files on an ExpressJS app. I usually don't do it in the routes, but I consider it as an 'initialization' process. It is possible to use ANY middleware twice or even more - as much as you want, keep that in mind.
I can setup Angular in my web app using ASP/Visual Studio rather easily, but I want to get into the Node world, more specifically Express. I'm not truly understanding a basic route handler for Express, that will support the paradigms that Angular has.
For example, when setting up an Express file, there's a million examples, but almost all of them use Jade for templating, and I'm against Jade's syntax and have no desire to utilize it.
So far, I have this for my Express server (I have commented out some questions regarding my decisions made so far):
var express = require('express'),
path = require('path');
var app = express();
var env = process.env.NODE_ENV || 'development';
// 1) Is this really necessary if I'm going to utilize Angular routing for views?
app.set('views', path.join(__dirname, '/app/views'));
app.use(express.static(__dirname + '/public'));
// 2) I'm assuming this is the desired pattern for utilizing Angular.
// A catch-all handler that serves up an html file, which will then
// hand off the rest of the routing to Angular?
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/index.html'));
});
const PORT = 3000;
app.listen(PORT);
console.log('Listening on port: ' + PORT);
The questions I have are:
Is app.set('views', ...) necessary in an Angular app through Express or is it really intended for a Jade/EJS templating workflow? If it's useful to Angular, what path should I point it to? My Angular views? Or just the static html file that will serve as the container to all angular views?
I'm assuming app.use(express.static(...)) is still needed for ensuring Express can serve up public static resources, like css/javascript.
Is an app.get('*', ...) { res.sendFile('path/to/index.html') } route handler the accepted pattern for serving up one html file, which will contain all necessary Angular usage?
For Angular, is it normal to only have one html file for the entire of your application, and then just use Angular's routing and controllers/views to handle the rest?
Is app.set('views', ...) necessary in an Angular app through Express or is it really intended for a Jade/EJS templating workflow? If it's useful to Angular, what path should I point it to? My Angular views? Or just the static html file that will serve as the container to all angular views?
If you need to render a view on the server side and then send it to the client, you need this. Otherwise (in your case) no. You can just send the file to the user or generate a user-specific output based on the parameters that user has sent to the server. It could be anything, HTML file, json or just simple text.
I'm assuming app.use(express.static(...)) is still needed for ensuring Express can serve up public static resources, like css/javascript.
You are right. If you need to serve the static content as well, the best way is to use express.static, however you can catch the requests and serve the content by yourself.
Is an app.get('*', ...) { res.sendFile('path/to/index.html') } route handler the accepted pattern for serving up one html file, which will contain all necessary Angular usage?
If for each and every other requests that the previous routes didn't catch, you need to send the exact same file, yes it is fine.
Remember if you need to serve other HTML files as templates and they are not in the same directory as you pointed in express.static to, the client could not have access to html files. I'll discuss it in a bit.
However, I believe it is a good practice to define all the routes and not just put a * to catch them all. It is better to define a pattern at least, it would be easier to maintain the code later on.
For Angular, is it normal to only have one html file for the entirety of your application, and then just use Angular's routing and controllers/views to handle the rest?
Depends on your application. In most of the cases yes.
I've done several big angular projects, I only have one route that actually serves the main html file, and one that serves static files (pictures, js, css). I also have a route that points to the templates directory which should be served as static contents. Those are the templates that AngularJS need to work with.
For the communication between your angular app and the server, you'll probably need other routes as well. You could create RESTful API end-points to create a communication layer for the client and the server.
I usually have these two lines in the server code to keep the all the templates in the same folder. It makes it easier to manage and define work flows:
app.use(express.static(path.join(__dirname, 'public')));
app.use('/templates', express.static(path.join(__dirname, 'templates')));
For communication between the server and the client:
app.post('/login', function (req, res) {
// deal with login information ...
res.send({
done: true,
errors: []
});
});
app.post('/search', function (req, res) {
// do the search ...
res.send({
done: true,
results: []
});
});
Remember if you use * at some point in your app, the other routes that you defined after that, will never catch the request.
And
I'm against Jade's syntax and have no desire to utilize it.
Yes, me too! But there are other options as well, I personally prefer ejs. If you are using express-generator you can just pass -e switch and it'll create everything compatible with ejs.
$ express -e
Also, take a look at here.