Serving a static html file from Express 4 - node.js

I want to serve a single html page using express 4. It was used to possible with previous versions of Express but now it tells me "No default engine was specified and no extension was provided". Many thanks in advance.
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
var router = express.Router();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static( path.join(__dirname, 'public')));
router.get('/', function(req, res) {
res.render('public/main.html');
});
module.exports = app;
library info below
"dependencies": {
"express": "~4.9.0",
"body-parser": "~1.8.1",
"cookie-parser": "~1.3.3",
"morgan": "~1.3.0",
"serve-favicon": "~2.1.3",
"debug": "~2.0.0",
"jade": "~1.6.0"
},
Below is the same example using Express 3 and it works as I would expect.
var express = require('express');
var path = require('path');
var app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get("/", function (req, res) {
res.sendfile('public/main.html');
});
module.exports = app;
Below is the correct way for serving a static html from Express 4. Thanks to E_net4 and NarendraSoni for their answers (1 and 2). For it to work you have to avoid using Express' router i.e. express.Router().get('/') as it will invoke the Express application's template engine.
var express = require('express');
var path = require('path');
var app = express();
app.use(express.static( path.join(__dirname, 'public')));
app.get('/', function(req, res) {
res.sendfile('public/main.html');
});
module.exports = app;

res.render would invoke the Express application's template engine, but you haven't specified one.
Express provides a sendFile function in the response object, which allows you to send static page files without passing through a template engine.
var router = express.Router();
router.get('/', function(error, res) {
var options = {root: __dirname};
res.sendFile('something.txt', options, function(error) {
if (error) {
res.writeHead(500);
res.end();
}
});
});
There's something else that looks fishy in your code. You have created a router, but you didn't show where it was included in your application. It may be happening that some other middleware that relies on a template engine is intercepting the request.
app.use('/', router);
Also note that you do not need to create a new router in this case. An Application already behaves like a Router.

You are doing everything right, except that there is a very minor mistake. :)
edit your route definition as :
app.get('/', function(req, res) {
res.sendFile('main.html');
});
Now since you have already included :
app.use(express.static(path.join(__dirname, 'public')));
so you don't need to append public with your main.html.
That's it, enjoy, your code should work now.

If you just need to serve one file, you can replace your router with:
var fs = require('fs');
router.get('/', function(req, res) {
fs.readFile('public/main.html', function (err, html) {
res.writeHeader(200, {"Content-Type": 'text/html'});
res.write(html);
res.end();
});
});

Techically speaking, if you only want to serve static html files, you only need this line:
app.use(express.static( path.join(__dirname, 'public')));
meaning that if you were to GET /main.html from your root directory, it would be statically served without having to type any further code.
By using:
app.get('/', function(req, res) {
res.sendFile('main.html');
});
You are using routes that are defined for the root of the express application, instead of the Router(), as explained in the express docs here:
A route method is derived from one of the HTTP methods, and is attached to an instance of the express class.
The following code is an example of routes that are defined for the
GET...methods to the root of the app.
// GET method route
app.get('/', function (req, res) {
res.send('GET request to the homepage');
});
So what's happening here is that you are using routes defined for the root of the express application, instead of routes defined for the express.Router().
If you wanted to use the Router() to route things the same way, you could try code like this:
//app.use(express.static(path.join(__dirname, 'public')));
var router = express.Router();
app.use('/', router);
/* GET home page. */
router.get('/', function(req, res) {
res.sendFile(__dirname + '/path/to/file.html');
});
So, you do not have to avoid using the express.Router(), you just have to use routes from the root of your express app, OR routes from the express.Router() in a slightly different way

Related

Express server middleware execute twice?

After trying to log some data on index file. I found my express server execute twice. Why do i get this error/bug?
Running Node 12.13.0 LTS, Express 4.17.1 and latest packages versions by the date of this post. I’ve tried on commenting some parts of code and always seem to end up running twice.
My app.js code:
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const path = require('path');
const bodyParser = require('body-parser');
const favicon = require('serve-favicon');
const app = express();
// ENV Variables
require('dotenv').config();
const PORT = process.env.PORT;
// Authentication Packages
const session = require('express-session');
const passport = require('passport');
// Middlewares
app.use(favicon(path.join(__dirname,'public','images','favicon.ico')));
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.json());
app.use(session({
secret: 'GBR6N7^?5Xx-Ldqxf&*-Hv$',
resave: false,
saveUninitialized: false,
//cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
// View Engine
app.use(expressLayouts);
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// Routes
app.use('/', require('./routes/index'));
// Controllers
app.use('/profile', require('./routes/profile'));
app.use('/products', require('./routes/products'));
app.use('/bookmarks', require('./routes/bookmarks'));
// Catch 404
app.use((req, res) => {
res.render('pages/404');
});
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
and my index.js code:
const express = require('express');
const router = express.Router();
// Official pages
router.get('/', (req, res) => {
// THIS IS THE CODE I GET TWICE ON CONSOLE
console.log(req.user);
console.log(req.isAuthenticated());
// THIS IS THE CODE I GET TWICE ON CONSOLE
res.render('pages/index');
});
router.get('/about', (req, res) => {
res.render('pages/about');
});
router.get('/features', (req, res) => {
res.render('pages/features');
});
// Footer pages
router.get('/terms', (req, res) => {
res.render('pages/terms');
});
router.get('/refunds', (req, res) => {
res.render('pages/refunds');
});
module.exports = router;
Also i have those two functions on my profile.js (for passport.js):
passport.serializeUser((userId, done) => {
done(null, userId);
});
passport.deserializeUser((userId, done) => {
done(null, userId);
});
I get those results twice:
console.log(req.user);
console.log(req.isAuthenticated());
Output (Executed twice!):
undefined
false
undefined
false
and I expect one:
undefined
false
Due to how Express routing works, the path / will match / and /about and /favicon.ico etc. This is because Express supports not just endpoint routing but also path mounting. In other words, express supports things like this:
const app = express();
const route = express.Router();
route.get('/world', (req, res) => { res.send('hello') });
app.get('/hello', route); // mounts world to hello
// so we can access /hello/world
In order to support the feature above, express needs to interpret paths such as /hello to mean both /hello and /hello/anything/else. It needs to treat it as both the endpoint and potentially just a path leading to an endpoint.
This means that if you have a path:
app.get('/', () => {});
It will also trigger if the browser requests /favicon.ico. And browsers request favicon.ico to draw the tiny icon in the browser tab. This is why your route is triggered twice.
A few things to keep in mind when writing Express routes/controllers:
Make sure that the / path is last because otherwise it will also respond to requests to all your other paths.
If you are using express.static() make sure it is set up before the / path. Yes, the first rule above should also cover this but I see this issue often enough that it merits its own point.
In your case you can possibly fix the issue by simply creating a favicon.ico icon and saving it in the static (public) folder.

Node js: getting an error Cannot GET /route when i use get method

When I use the "use" method my code works fine, but when I use the "get" it gives an error: "Cannot GET /route1".
My Code:
const express = require('express');
const app = express();
const expbs = require('express-handlebars');
const path = require('path');
const routes = require('./routes/handlers');
app.use(express.static('public'));
const hbs = expbs.create({
defaultLayout: 'main',
layoutsDir: path.join(__dirname, 'views/mainLayout'),
partialsDir: path.join(__dirname, 'views/pieces'),
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.get('/route1', routes);
app.listen(8080, () => {
console.log('Server is starting at port ', 8080);
});
I am new to node js, please tell me can i define routes with "get" method.
I believe your routes/handlers.js look something like this
var express = require('express');
var router = express.Router();
function greetUser(req, res){
res.send("Welcome dear user");
}
router.get("/", greetUser);
router.post("/", (req, res)=>{ res.send("user registered") });
module.exports = router
The problem here is this last line, this router object which is being exported works fine for app.use middleware, while .get or .post expects 2nd parameter to be a function
If you export this greetUser function from your router as well or receive this function from anywhere, this should start functioning well. Practically it would be
app.get("/route1", (req, res)=>{ res.send({status : true, message : "sample JSON"})})
If you are using router you coudn't use get method.
Here is the docs.
Only the handler has access to get method. app.use will add path to api route which point to get,post and etc.
You could only explicitly define a get as a standalone get route.
app.get('/route1', (req, res) => {
res.send("You have hit route1 - get");
});
When using router you could only include the router object as a parameter in app.use(path, routerObj) method.
app.get('/route1', routes);
woulde be app.use('/route1', routes);

All pages return the same content with OVH Cloud Hosting

I've recently completed a Node.js website locally, which works fine, though I have noticed some issues when uploading the website online to OVH Cloud Web Hosting. All pages, even those that should not exist, return the contents of the homepage.
I'm running Express with Node.js, and the file structure was created with express-generator. My app.js file contains the following:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var expressHbs = require('express-handlebars');
var Handlebars = require('handlebars');
var HandlebarsIntl = require('handlebars-intl');
var mongoose = require('mongoose');
var indexRouter = require('./routes/index');
var blogRouter = require('./routes/blog');
var blogItemRouter = require('./routes/blog-item');
var portfolioRouter = require('./routes/portfolio');
var contactRouter = require('./routes/contact');
var iBlogPostsRouter = require('./routes/i/blog-posts');
var iContactRouter = require('./routes/i/contact');
var iPortfolioItemsRouter = require('./routes/i/portfolio-items');
var portfolioItemRouter = require('./routes/portfolio-item');
HandlebarsIntl.registerWith(Handlebars);
var app = express();
// view engine setup
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');
app.disable('etag');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/blog', blogRouter);
app.use('/blog/:title', blogItemRouter);
app.use('/portfolio', portfolioRouter);
app.use('/contact', contactRouter);
app.use('/i/blog-posts', iBlogPostsRouter);
app.use('/i/contact', iContactRouter);
app.use('/i/portfolio-items', iPortfolioItemsRouter);
app.use('/portfolio/:title', portfolioItemRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {title: err.status + ' ' + err.message});
});
module.exports = app;
All of the routers have the same code, except render a different template. Here is an example of the indexRouter:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'About', about: true });
});
module.exports = router;
The issue is that every page, even my .js and .css files, returns the HTML from whatever is in the app.use('/' ...) router. The console returns the following error:
Resource interpreted as Stylesheet but transferred with MIME type text/html: "https://xxx.co.uk/core/styles/m.css".
I experimented with this by changing the homepage to be my contact page, which has resulted in every URL returning the contact page. My CSS and JavaScript are in a public folder. The only thing that I can think of is that the '/' route is somehow being used for every single request, but it doesn't make any sense to me why this could be happening.
Instead of using app.use('/<route>', <router>) in your project, try replacing it with the corresponding express statements, e.g,
router.<route_method>('/<route>', function(req, res, next){
// code
});
See if it works fine or not.
The reason your site is defaulting to the '/' route is because you haven't properly set up your routes. Each router module needs to know what is getting exported. Your indexRouter file, for example, needs to look like this:
var express = require('express');
var router = express.Router;
router.get('/', function(req, res){
res.render('index', { title: 'About', about: true });
});
module.exports = router; <<----
In addition, if the app.js you're showing as of 09/04/2018 06:36 is the complete app.js, you're missing a lot. You have a minimized CSS as your first stylesheet, which actually contains the rendered index.html.

NodeJs routes not working from inner page

I am trying to develop an application in NodeJs using express framework. My routing is working when I navigating from home to inner pages. But If I want to navigate from some inner page to homepage then it is not working.
Below is my app.js code.
const express = require('express');
const path = require('path');
const engines = require('consolidate');
const bodyParser = require('body-parser');
//declare all routers
var home = require(path.join(__dirname, "/routes/index"));
var myaccount = require(path.join(__dirname, "/routes/myaccount"));
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.engine('html', engines.handlebars);
var defaultViewPath = path.join(__dirname, "/views");
app.set('views', defaultViewPath);
app.set('view engine', 'html');
app.use('/', home);
app.use('/myaccount', myaccount);
Here if I have navigated from home to myaccount - Its working
But if I am navigating from myaacount to home - It reloads the same page.
Can anyone help me to resolve this issue.
To define routing using methods of the Express app object, use app.get() to handle GET requests
var express = require('express')
var app = express()
// When GET request is made to the homepage
app.get('/', function (req, res) {
res.render('home');
});
// When GET request is made to the myaccount
app.get('/myaccount', function (req, res) {
res.render('myaccount');
});
app.get('/myaccount/innerpage', function (req, res) {
res.send('Hello Inner Page');
});
//Page Not Found
app.use(function(req, res){
//render the html page
//res.render('404');
res.sendStatus(404);
});
Hope this could help you
use app.get and app.post Route Methods
app.get('/',function(req,res){
res.render('home');
});
app.get('/myaccount',function(req,res){
res.render('myaccount');
});
Or Create Router File For Home & myAccount
var express = require('express')
var router = express.Router()
router.get('/', function (req, res) {
res.send('Home Page')
})
module.exports = router
in Your app.js or index.js file , require route.js
var home = require('./route');
app.use('/', home)

Node.js sending html file doesn't load linked files (css, js)

I am trying to make az ExtJS application with a Node.js server. My server code currently looks like this:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.sendfile(filedir + '/index.html');
});
app.get('/employees', function(req, res){
console.log("hello");
});
app.listen(3000);
When I open localhost:3000 in a browser, the html file is load, but not correctly. Checking in firebug I see that itt cannot find the linked files in html. For example
"NetworkError: 404 Not Found - http://localhost:3000/ext-4/ext-debug.js".
This is quite logical, since the file doesn't exist on that URL. My question would be how to fix this issue, so it could find every single linked file on my filesystem.
I'm clearly doing something wrong or missing something, I am totally new in node.
Doesn't look like you're configuring Express' static file handler.
Try adding this code:
app.configure(function() {
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.bodyParser());
app.use(express.logger("short"));
});
It would go right after var app = ... like this:
var express = require('express');
var app = express();
app.configure(function() {
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.bodyParser());
app.use(express.logger("short"));
});
app.get('/', function (req, res) {
res.sendfile(filedir + '/index.html');
});
app.get('/employees', function(req, res){
console.log("hello");
});
app.listen(3000);
And then place your static files under the ./public directory.
You'll want to use some static middleware such as: http://www.senchalabs.org/connect/static.html
note express inherits connect so you can
app.use(express.static(filedir));
Or the full thing:
var express = require('express');
var app = express();
app.use(express.static(filedir));
app.get('/employees', function(req, res){
console.log("hello");
res.send("hello");
});
app.listen(3000);

Resources