Why is Express redirecting infinitely redirecting me? - javascript

I am trying to setup a multi language website with Express and NodeJs. My problem is I get redirected what it feels like 100 times and my browser is giving me a error that the webpage is not working because it redirected me too many times.
app.js
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
app.use('/:lang', indexRouter);
app.use('/:lang/users', usersRouter);
index.js (indexRouter)
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;

The problem is that this route handler:
app.use('/', (req,res,next) => {
res.redirect('/en-US');
next();
});
will get hit for not only /, but also /en-US. app.use() matches any route handler for which the path is equal to or a subset of the requested path. So, the browser requests "/", you redirect to "/en-US", which then redirects to "/en-US" and so on, an infinite loop.
I don't know the overall URL design of your site to know what the best overall solution is. You can prevent the infinite redirect loop by just changing app.use() to app.get():
app.get('/', (req,res,next) => {
res.redirect('/en-US');
});
But, that will make the redirect only work for GET requests which may or may not be OK. If you want all HTTP verbs to redirect, you could change to app.all():
app.all('/', (req,res,next) => {
res.redirect('/en-US');
});
The important thing to understand here is that app.get(), app.post(), app.all(), etc... all require an exact match for the URL path, whereas app.use() just requires a subset match. This is a little understood aspect of the Express design.
In addition, remove the call to next() after you do res.redirect(). At that point, you've sent the response, you don't want any other request handlers to see the request. You're done with routing.

under your app.js
Try using
app.use('/', router )

How about you try dealing with the '/' route through the app.js directly instead of index.js

Related

Express.js match only exactly '/' route

So I'm serving a web page on the root route '/', and this page had an authentication middleware. Using regular
app.use('/', authorizeFront, express.static('../client/dist'));
would cause every route to be authenticated, which is what I'm trying to avoid. I've also tried using regex to match exactly '/' but it doesn't seem to be working.
app.use('/^/$/', authorizeFront, express.static('../client/dist'));
Is there any official way to do this? Thanks!
Another way to do this could be:
app.use("*", (req, res, next) => {
if (req.baseUrl === "") { // For / requests baseUrl will be empty
// Call authenticator and then call next() if auth succeeds else call next(err)
} else {
console.info("Bypassing Authentication");
next();
}
});
This will hit the middleware for all requests, but you have the control for which request you want to call the authenticator.
app.use does a partial match. Use app.get instead.
When using app.use("/") this will match any path and method that starts with "/",
This happens because app.use() is intended for global middlewares.
Instead you can use app.get("/", yourTargetedMiddlewaer) to target a specific route and a specific method (GET) in this case.
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
if ( req.path === "/") {
console.log("request matches your special route pattern", req.url);
// return authorizeFront(); call your code
}
next();
});
app.use('/', indexRouter);
app.use('/users', usersRouter);
I tested this and my console prints only when i use URL like this:
http://localhost:3000/ or http://localhost:3000
Also notice the sequence of middleware I have used, base root middleware should be set at top.
You can do more modification as per your needs

Express Router not showing endpoint requests

I'm new to express and I'm trying to use express.Router() in order to route to different end points. When I follow tutorials online, I can only get text to send from the root '/' and no other endpoint. As far as I can tell my code matches well with the tutorial, so I'm not seeing where something is missing.
express.js
"use strict";
const express = require('express');
const app = express();
const resources = require('../routes/resources');
const commonExpress = require('common/lib/express');
commonExpress.setup_pre(app);
app.use('/', (req, res) => {
res.send('<h1>Hey Socket.io</h1>');
});
app.use('/resources', resources)
//use /routes/resources to handle endpoints
//that start with '/resources'
commonExpress.setup_post(app);
module.exports = app;
resources.js
"use strict";
const express = require('express');
const router = express.Router();
router.use(function(req, res, next) {
console.log(req.url, "#", Date.now());
next();
});
router.route('/messages').get((req, res) => {
res.send("hi get /resources/messages")
}).post((req, res) => {
res.send("hi post /resources/messages");
});
router.route('/messages/:userId').get((req, res) => {
res.send("hi get /resources/messages " + req.params.userId);
}).put((req, res) => {
res.send("hi put /resources/messages " + req.params.userId);
})
module.exports = router;
commonExpress
const express = require('express');
const logger = require('morgan');
const utils = require('./utils');
const cookieParser = require('cookie-parser');
module.exports = {
setup_pre: app => {
app.use(logger('dev'));
app.use(express.json());
app.use(cookieParser());
app.use('/health', (req, res) => res.status(200).send());
},
setup_post: app => {
app.disable('x-powered-by');
app.use(utils.handleMezError);
app.use(utils.handleMongoError);
app.use(utils.handleUnknownError);
app.use(function (req, res, next) {
res.status(404).send();
})
}
};
These are the responses I get when I use the curl command:
tk#tk-desktop:~/messenger$ curl http://localhost:4000/
<h1>Hey Socket.io</h1>tk#tk-desktop:~/messenger$ curl http://localhost:4000/resources
<h1>Hey Socket.io</h1>tk#tk-desktop:~/messenger$ curl http://localhost:4000/resources/messages
<h1>Hey Socket.io</h1>tk#tk-desktop:~/messenger$ curl http://localhost:4000/resources/messages/:userId
Your code here:
app.use('/', (req, res) => {
res.send('<h1>Hey Socket.io</h1>');
});
grabs all possibly URLs and sends a response and does not allow any of the other request handlers to see inbound requests. Since request handlers in Express are processed in the order you register them, the only request handlers that can run before this one grabs the inbound request are the ones in commonExpress.setup_pre(app);.
Probably, you want to change that above route to:
app.get('/', (req, res) => {
res.send('<h1>Hey Socket.io</h1>');
});
So, it only responds to a GET request and so it only matches the exact / URL (see details below).
It may help you to understand a few things:
app.use() is greedy. It will match any inbound URL that starts with the path you use. So, if you have app.use('/', ...), that will match all possible URLs since all URLs start with /. As such, app.use() is usually used for middleware, that prepares a request/response, but doesn't actually send one and then calls next() to continue routing to subsequent handlers and doesn't call res.send() or any other method that sends a response. Once you've sent a response and not called next(), all routing is done for that request.
Inbound requests are processed by Express in the order the request handlers are registered. So, if you have overlapping handlers, you would generally put the more permissive handlers later and the more specific handlers earlier. If you do the reverse which is what you have here, the more permissive handlers will grab everything and the others will never get a shot.
It looks like you can either change your app.use('/', ...) to an app.get('/', ...) which will only match the exact / URL and nothing else or you can change it to be a middleware handler that doesn't send a response and does call next() to continue routing.
It also looks like you may be using app.use() in other places where app.get() is more appropriate. For example with app.use('/health', ...), app.use() will match all HTTP verbs (GET, POST, PUT, DELETE, PATCH, etc...), but if you are sending a response in your route handler, you typically want to be matching only one of those verbs. If it's a request/response type of route where the browser requests content, that would be a GET and should use app.get(), not app.use().

How to protect a route with a referrer in Node.js

I am trying to protect a route in my node.js application such that if the user wants to go to the page /post they have to come from /blog. If the user comes from anything other than /blog they are to be redirected to /. I have the following code that uses the http referrer
let ref = req.headers.referer;
if ((ref === undefined) || (!ref.includes('blog'))) {
res.redirect('/')
}
It seems to work well if I console.log for testing but if I do res.redirect, I get the error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.
How can I use the referrer to protect the route.
Should there be any other way of accomplishing this without using referring: all suggestions are welcome.
Thanks in advance
Try this, In your app.js file include this.
const express = require('express');
const app = express();
app.get('/',(req, res, next)=>{
res.send('Ready')
});
app.get('/test',(req, res, next)=>{
res.send('Ready')
});
// Below (*) will consider unwanted urls
app.use('/*', function(req, res, next) {
res.redirect('/')
});
app.listen(4000);
FYI, If you try demo.com/unkownurl will redirect to root like demo.com/

app.get() being called multiple times express

I'm fairly new to node.js and trying to make a simple website which first asks the authentication and then redirects the user to a page.
so, what i do is that i create a middleware which listenes to every request made to my website.
what this middleware does that it checks if the the user is logged in with my website or not is yes then redirect to the requested page if not, then redirect to the login page, here is my code for that.
var express = require('express');
var app = express();
// middleware for using static files
app.use('/public', express.static(__dirname + '/public')); // all the js files for check_before.html
app.use('/templates', express.static(__dirname + '/templates')); // here are css/js files for login.html
// setting up views folder
app.set('views', __dirname + '/views'); // check_before.html is sitting here
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use((req, res, next) => {
res.render('check_before.html');
// here in the html I implement the logic using js files which are located in public folder.
next();
});
// if not logged in , the user gets here
app.get('/login', (req, res, next) => {
res.render('login.html')
});
// if logged in redirect to some page
app.get('/welcome_page', (req, res) => {
return 'welcome'
});
everything goes well untill the user hits the http://localhost:8000/login page (after the check if they are signed in or not) the page keeps on loading multiple times and it won't stop reloading.
I have defined all the css, js files of login.html page in the templates folder which is loaded above the middleware by reffereing to this question
Express middleware getting called many times. could that be a problem?
what could be the reason for this?
here is the error i'm getting in the console.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
any guesses?
Edit1
I went through this question Error: Can't set headers after they are sent to the client , and i guess it concludes that setting headers explicitly could be problematic.
Could this be a reason? because in my logic if the user is not signed In, I'm just using window.location.replace('http://localhost:8000/login') to redirect the user to login page.
should I use any another method for redirection?
Edit2
There are suggestions that i must write a middleware to check is the user is authenticated or not, and get a sort of flag for that, but as i've stated above that i'm implementing the logic in check_before.html(client side). so it won't be possible to use that.
I have two guesses:
You shouldn't call send (or any other function )after res.render.
Middleware to verify user is logged in should be something like this (applied only to routes you want to verify user)
Middleware should be something like this
const isAuthenticated = (req, res, next) => {
if(req.isAuthenticated()) {
next();
} else {
res.redirect('/');
}
}
app.get('/welcome_page', isAuthenticated, (req, res) => {
return 'welcome'
});
The reason is that middleware is called before your /login request. To fix it, you need to modify your middleware function. It should be something like:
app.use((req, res, next) => {
if(isLoggedIn) { //isLoggedIn is a flag that checks whetehr user is logged-in or not
res.render('check_before.html');
} else {
// here in the html I implement the logic using js files which are located in public folder.
next();
}
});

Make express ignore certain URL changes

I try to make a Single Page App on Express. The main problem is that I use Express route feature, that re-renders the view each time the URL changes and GET request gets to server. I have a rather usual code like:
// Express routes
var routes = {
index: require('./routes/home')
};
// use routes
app.use('/', routes.index);
//home.js
var express = require('express');
var router = express.Router();
router.get('/', function (req, res, next) {
res.render('home', {title: "ITEF"});
});
router.get('/about', function (req, res, next) {
res.render('home', {title: "ITEF"});
});
Is there any way to make router ignore URL changes and let the front-side app be as it is? The plan is to buld all UX logic according to URLs, but without countless re-rendering.
Found out that it's rather easy with pushState HTML5 feature:
window.history.pushState('object or string', 'Title', '/about');
Details described in a good article here.
I little bit late for answering, but I managed to do what you asked using a library called Finch.js.
So, when I want to call another URL in my Single Page Application, I use Finch.navigate('/profile'). The URL will change, and there will be no call to the node server.
Finch.route("/profile", function () {
main.viewModel(new app.model());
});
Finch.listen();
Finch.navigate('/profile');
You can learn more about the library here FINCH

Categories