properly handle a 404 in expressjs - node.js

A little baffled at how to best handle 404 cases in my app. Here is a gist of a very basic example.
//******************************
// BUILD THE HTTP SERVER
//******************************
var express = require('express');
var app = express.createServer();
app.get('/login', function(req, res){
console.log("hit the login");
res.send('you hit the login');
});
app.get('*', function(req, res){
console.log("got a 404");
res.send('what???', 404);
});
app.listen(8081);
console.log('Server started on port: 8081');
If I fire up the server and hit the index of the server "/" I properly get the 404 message, HOWEVER, in the logs are 2 "got a 404" log entries on the console... odd.
So if I hit the "/login" page I do get the proper page, and corresponding message to the console, BUT, I ALSO get the 404 message to the console too?
Is this the expected behavior? I am using the latest 2.5.4 express on 4.11 but have tried it on other versions of node with the same results.
I dont really like the fact that my 404 route gets called on every single request, I must be doing something wrong.

This is probably due to fact that browser trying to get also favicon for your page.
Just use express.favicon() creating your server:
express.createServer(
express.favicon()
);
You may also want to use logger to discover thing like this, it's really useful middleware.

Related

Node/Express Server on DigitalOcean only responding with "/" route even if I hit "/test" route

I'm trying to host a Node.js/Express server for the first time, and I'm currently attempting to use Digital Ocean's App Platform. I have it up and running, but my routes aren't working correctly. Digital Ocean allows me to set HTTP Request Routes, and I have "/" and "/test" set for two of them. No matter what route I hit, it only ever responds with the "/" route.
Here is my code for reference:
require("dotenv").config();
const { SERVER_PORT } = process.env;
const express = require("express");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.status(200).send("This is the / route")
})
app.get("/test", (req, res) => {
res.status(200).send("This the /test route");
})
app.listen(SERVER_PORT, () => {
console.log(`Server running on port ${SERVER_PORT}`);
});
When I make a GET request to "https://{DigitalOceanURL}/", I get the correct response of "This is the / route", however when I make a GET request to "https://{DigitalOceanURL}/test", I still get the response of "This is the / route" and not "This the /test route" as is in my code.
If I try and make request to a route that doesn't exist, however, such as "https://{DigitalOceanURL}/doesntexist" I get the response "Cannot GET /doesntexist". To me this suggests that the routes I'm entering into DigitalOcean are registering, but for some reason it's not seeing anything past the initial "/" in the route.
I've been trying to Google for a while now and I can't seem to diagnose what's wrong. I thought it might be something with app.use vs app.get, as on this answer on a SO post it says that app.use "...will match all requests beginning with..." your route, whereas app.get "...matches only GET request with exact match.". So it seems that, since I'm hitting the exact route, it should be working? But it feels like the general area of my problem, as it seems to only be registering the "/" in the route and nothing else?
Both the endpoints work when running the server on localhost, so it seems like there must be some disconnect with DigitalOcean.
Any help would be greatly appreciated - as I mentioned this is my first time trying to host and it's a bit overwhelming.
Thank you!
The issue was with my Digital Ocean settings. As I said in my question: "Digital Ocean allows me to set HTTP Request Routes, and I have "/" and "/test" set for two of them." It worked when I removed the "/test" route and only had one, "/" in my Digital Ocean settings. I interpreted it as "List all routes I had in my express app", but I guess that's not what it meant. There only should've been one set: "/".
Your / route declaration comes before the one for /test. Express matches in code order, so / picks up every incoming request, and none make it to the more specific route. Switch their order.
This isn't specific to Digital Ocean, of course.

too many redirects in express

I want to handle all my cookies and session stuff in a function then redirect to the destination path. I use this function in Express:
app.all('*', function(req, res, next){
if('_id' in req.session)
next()
else if('userInfo' in req.cookies){
req.session._id = req.cookies.userInfo._id
next()
} else {
res.redirect('../login')
}
res.end()
})
but browser print this error:
net::ERR_TOO_MANY_REDIRECTS
what's the problem?
This error occurs when a web browser is redirecting you to another web page which then that web page redirects you back to the same browser again. Your configurations are wrong. app.all('*', ..) runs again and again whenever a request is made, which causing repetition.
You need to have better configurations than app.all(*..) //all. You need to specify it more so that it doesn't repeat itself.
I would say limit it down to some urls and not all of them. You could do
app.get('/cookieCheckerPage', function(req, res){
//code here
});
Also please see Error 310 (net::ERR_TOO_MANY_REDIRECTS):

Node.js and Express not working?

I am currently trying to learn implementing RESTful APIs using Node.js & Express. Using this tutorial: http://code.runnable.com/U7bnCsACcG8MGzEc/restful-api-with-node-js-express-4
I created each file on my local drive and tried running the code using node server.js..However I kept on getting an error. Why might be causing this?
The code you chose to run is only routing requests for urls that begin with /api as you can see here:
app.use('/api', router);
On top of that, the routes it accepts are /players and /player/:id:
router.get('/players', function(req, res, next) {
res.json({ players: players.getAllPlayer() });
});
router.get('/players/:id', function(req, res, next) {
var player = players.getPlayerById(req.params.id)
res.json(player);
});
For every request, including the routes above, it outputs the method and url to console.log.
Even when it fails to get /, you should see GET / in your console.
Now try to access this url: 0.0.0.0:8080/api/players
It works, right?

Express not catching request to '/'

I have a quite bizzare issue - somehow, Express does not capture my request to my root route.
My Route File looks to following:
'use strict';
var errors = require('./components/errors');
var auth = require('./controllers/auth');
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
module.exports = function(app) {
// Insert routes below
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
app.route('/login')
.get(auth.login)
.post(auth.loginUser);
app.route('/logout')
.get(auth.logout);
// All other routes should redirect to the index.html
app.route('/*')
.get(ensureLoggedIn('/login'), function(req, res) {
console.log("req to /");
res.sendfile(app.get('appPath') + '/index.html');
});
};
So what happens:
I request '/' and it sends me directly to my root and the app runs. Except: It does not require me to login, and also the Log Output does not show that any request has been made.
If i request '/users' (Angular Route) it redirects me to '/login', as expected and then continues on its path.
Any idea what would be causing this behavior?
Are you exposing any static assets with express? If you are and you require your routes after you expose the assets, the request to "/" will just land in your public folder and do nothing.
Does this help? Could you post your server.js?
I ran into this issue earlier and it was driving me nuts.
It seems like it's related to the filename of the 'main' Page being served, before Angular takes over.
Originally, the file was names index.html which, as it seems like, prompted Node to serve it by default - Which is expected behavior, if no routes interfere.
After renaming the main file to application.html and changing the serve asset - all is well, problem solved.
I am still unsure though, why the Route would not fire and the index would overwrite it.

URI bind Express.js

Hello I want to bind the URI of my app, for example lets imagine this scenario.
I am running express app on port 3000,
nginx on port 80, proxying requests of URI api to port 3000
And have this route on express
// Home
app.get('/', function(req, res) {
res.send('Hello!');
});
If I try access from localhost:3000 I get Hello! in my browser (that's expected),
but if I try to access from localhost/api I will get an error, of course he can't find the route I'm tryng to access.
If I change app.get to app.get('/api/... it works as expected, but this isn't what I want... I would need to prepend api in every route, there must be another way to do this, something like:
URI binding
URI filter ??
I read the documentation but can't find anything to solve my problem, and I'm thinking of doing a package that does URI bindings on express to solve this problem.
See my answer here for a solution that lets you point every request matching a leading /api to a particular express app. In the linked case, the user wanted to do some things without the leading fragment. You could leave out the app.use(app.router) for the main express app since you only care about the /api/ routes.
<snip>
var http = require('http');
var express = require('express');
var desktopApp = express();
var mobileApp = require('./mobile.js');
desktopApp.use('/mobile', mobileApp)
desktopApp.use(desktopApp.router);
</snip>
Also I am pretty sure that you can actually rewrite request.url yourself. I have never tried this so I can't promise it works! see docs http://expressjs.com/4x/api.html#req.originalUrl Also be sure to put this at the very top of your routing functions, so it is executed before any subsequent routes.
app.all('*', function(req, res, next){
req.url = req.url.replace(/^\/api/, '');
//the regex replaces leading /api with empty string
//req.originalUrl will keep the old url
next();
});

Resources