NodeJS response not sending index.html - node.js

app.get(`/`, (req, res, next) => {
console.log(`in / get`);
const indexHtml = path.resolve( __dirname + '/../public/index.html' );
res.sendFile(indexHtml);
next();
});
I'm trying to make this index.html show up on my home route using express but it's not loading. I get the console log, and I've console logged indexHTML to ensure the path is correct, but all I get is an error of cannot get.
All my other routes that are brought it are working a-ok. Just not this guy.

Remove the call to next() after res.sendFile(). You want the res.sendFile() to handle the response entirely, but calling next() passes on control to other handlers, probably ending up in the 404 handler and because that doesn't have to read the disk, it gets processed before res.sendFile() does it's job.
When you send the response, you do not want to call next() because you don't want any more request handlers in the chain to run.

Related

Using sentry with a custom error handler in Express

I have an Express server running for the backend of a website with Sentry (v5.15.5) successfully implemented. I'm now trying to improve the error handling on the backend, as at the moment if something goes wrong with the request, the request is not ended and the client sits there waiting for a response, which it never gets.
To tell the client if the request has failed I'm using the custom error handler in the documentation:
app.use(function onError(err, req, res, next) {
// The error id is attached to `res.sentry` to be returned
// and optionally displayed to the user for support.
res.statusCode = 500;
res.end(res.sentry + "\n");
});
However, when I use this on my server, only the custom error handler runs - Sentry never creates an event for the error, but if I just use another custom error function, they both get called fine, which makes me think this is a Sentry issue. Here's the relevant parts of the server code:
...
const Sentry = require('#sentry/node');
...
const app = express()
Sentry.init({ dsn: process.env.SENTRY });
...
// Middlewares
app.use(Sentry.Handlers.requestHandler());
app.use(express.json())
app.use(helmet())
app.use(cors())
app.use(morgan('tiny'))
const controllers = require('./controllers')
const wrap = fn => (...args) => Promise
.resolve(fn(...args))
.catch(args[2])
// Routes
...
app.post('/test', authUser, wrap(controllers.testController))
...
app.use(Sentry.Handlers.errorHandler());
app.use(function onError(err, req, res, next) {
res.statusCode = 500
res.end(res.sentry + "\n")
})
app.listen(PORT, () => console.log(`APP RUNNING ON PORT ${PORT}`))
The controllers on the server make database requests, etc. so they are async functions - that's why I use the wrap function to catch promise rejections and pass them to the error handler. If I unwrap the controller then Sentry works fine, but then the server never sends the error to the client.
I expect I'm probably going about this wrong as it should be pretty simple to do, but no matter what I do I cannot get Sentry + async controllers + custom error handler to work. Any help would be appreciated.
(This may be an Express issue, if so let me know and I'll take it over there)
Thanks
For some reason Sentry's 'Filter out localhost' option (which was turned off but somehow got toggled on) doesn't actually filter out all local errors. When I removed the custom error handler and wrap function, the errors managed to get past the localhost filter. After I turned it back off all the errors came through on Sentry fine.

express middleware functions invoked twice when request is made from browser

Below is my nodejs code
const express = require('express');
const app = express();
app.use('/', (req, res, next) => {
console.log("In interceptor");
next();
});
app.use('/users', (req, res, next) => {
console.log('In /users middleware');
res.send('<h1>From "/users" handler </h1>');
});
app.use('/', (req, res, next) => {
console.log("Default handler");
res.send('<h1>From default handler</h1>');
});
app.listen(3000);
Console output when a request is made from browser (both chrome and edge)
http://localhost:3000
******************
In interceptor
Default handler
In interceptor
Default handler
******************
http://localhost:3000/users
******************
In interceptor
In /users middleware
In interceptor
Default handler
******************
But when a request is made using curl, I don't see multiple invocations
curl http://localhost:3000
******************
In interceptor
Default handler
******************
curl http://localhost:3000/users
******************
In interceptor
In /users middleware
******************
Can someone explain why middleware functions are invoked multiple times when request is made from browser?
The usual reasons you see multiple requests when a page loads from a browser are one of two things:
The browser automatically requesting the favicon.ico file.
The browser attempting to load some resource from the HTML file (script file, image, CSS file, etc..)
You can see exactly what each request is for by adding:
console.log(req.url);
to your middleware.
Found that it is happening due to /favicon.ico request made by browser. Adding specific handler (shown below) prevented default handler from being called twice
app.use('/favicon.ico', (req, res, next) => {
console.log('favicon handler');
res.sendStatus(200);
});

Does res.send() in an Express JS handler automatically call next()?

I understand that one can call next after res.send in an ExpressJS handler, but does res.send 'automagically' call next in any case?
I have the following code
const express = require('express');
var app = express();
app.get('/', (req, res, next) => {
console.log('in route handler')
res.send('Hello World')
});
app.use((req,res, next) => {
console.log('in middleware')
console.log('...........')
})
app.listen(process.env.PORT || 8080)
My console log is
in route handler
in middleware
...........
If I do indeed call next explicitly after res.send I get
in route handler
in middleware
...........
in middleware
...........
and thus it would seem the middleware is being called twice.
Why is this? Is it because the middleware is also called 'directly' in some fashion, regardless of the route? That is, it is simply always called, even when it is after the route handlers? But I thought if it was after the route handlers, to reach the middleware the route handler preceding it has to call next, as here https://derickbailey.com/2016/05/09/in-what-order-does-my-express-js-middleware-execute/, where it says "It turns out the order in which you add the middleware is important. And since the 2nd 'use' method is added after the 'get' handler, it is never called. The 'get' handler short-circuits the middleware when it renders the page, preventing any further middleware from being processed."
Express version 4.16.0, Node version 11.2.0
Thanks for any clarification!
Why is this?
It's because browsers send an additional request to get favicon; When you go to localhost:8080 chrome ( or firefox ) sends a get request to / hence your server matches this route and logs:
in route handler
Immediately after that it sends a second get request to /favicon.ico but your server does not match any route. it continues its way to middlewares mounted after routing and so logs:
in middleware
...........
Of course by calling next() you've called your middleware explicitly after two above request and so:
in route handler
in middleware
...........
in middleware
...........
But I thought if it was after the route handlers, to reach the
middleware the route handler preceding it has to call next
Of course you are right. Add serve-favicon middleware to your app and your custom middleware never get called without calling next() explicitly unless none of the routes does not get matched:
const express = require('express');
var favicon = require('serve-favicon')
var path = require('path')
var app = express()
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
app.get('/', (req, res, next) => {
console.log('in route handler')
res.send('Hello World')
});
app.use((req,res, next) => {
console.log('in middleware')
console.log('...........')
})
app.listen(process.env.PORT || 8080)
By the way this middleware mounted after all routes is proper place for handling 404's because if we get to this point, none of our apps routes got matched.
app.use()
Middleware allows you to have set of actions which your routes should follow. Consider as if all your routes will do some processing before actually performing designated action for that route.
When I ran your code it printed below and Hello World was rendered in both Mozilla(Version 63.0.3 (64-bit)) and Chrome(Version 71.0.3578.80)
in route handler in middleware ...........
res.send()
Now coming to your question, no there is no need to call next() after res.send() is called. Because as soon as it is encountered, it'll send the response immediately. And yes you are correct the order of middleware does matter. So when you added next() after res.send() following actions were performed:
First the '/' route will return Hello World on the browser stop loading
Your middleware will be called twice, once due to next() and 2nd time due to middleware itself.

Not able to receive empty get request with express static in nodejs

I am trying to fetch web pages using express static and below is the server code.
app.use(express.static('DIR/webfiles'));
app.get('/test', function(req, res) {
console.log("got req");
res.sendfile("login.html");
});
app.get('/', function(req, res) {
console.log("got req");
res.sendfile("login.html");
});
when I request for localhost:port/test (from browser), I am able to see login.html page and it prints "got req" on server end but when I request for localhost:port or localhost:port/ , I am getting some other file in webfiles folder. It does not print "got req". Is empty GET handler overridden by express static?
When I remove "app.use(express.static('DIR/webfiles'));" line, it is able to get empty GET request but doesn't work in way I want it to. Why it is not getting empty request and how to handle empty requests.
Express will process the various route handlers (including the static middleware) in order of declaration.
If you request /, the static middleware will check for a file called webfiles/index.html, and if it exists, it will be returned.
To override this behaviour, make sure that you declare your own route handler before the static middleware declaration:
// This will match requests to `/` and since it's declared before
// the static middleware, it will get to handle those requests.
app.get('/', function(req, res) {
console.log("got req");
res.sendfile("login.html");
});
app.use(express.static('DIR/webfiles'));

Express middleware before response is carried out to client

I need to modify the response data a module sends to the client, as the module uses res.send i can't seem to figure out a way for me to modify the data before it's carried out to the client.
Is there any kind of middleware/event that I can use to catch the res.send and modify the data before its executed?
I am aware that router.use exists but it's called before the router.post function and not before the res.send is sent to the client. So I need some kind of middleware which is called after the router.post function is done but before anything is sent to the client.
Well you can override the send function:
app.use(function (req, res) {
var send = res.send;
res.send = function (body) { // It might be a little tricky here, because send supports a variety of arguments, and you have to make sure you support all of them!
// Do something with the body...
send.call(this, body);
};
});
If you want to support more than just calling send(like calling end method), then you have to override more functions...
You can check connect-livereload on how it adds a script to any html output.
One more solution from here:
expressApp.use(function (req, res, next) {
req.on("end", function () {
console.log('on request end');
});
next();
});
Important Note: To work, this needs to be placed before body parser since it recreates the response object. see this answer
It can be done by overriding res.send
We override the res.send function to capture the response body in our API analytics tool as follows
// It will monkey patch the res.send.
// The patch intercepts the send invocation, executes is logic such as atatus.setResponseBody
// then restores the original send function and invokes that to finalize the req/res chain
const resSendInterceptor = (res, send) => (content) => {
// Set response body in Atatus Analytics
// Atatus is our API analytics tool
atatus.setResponseBody(content || '');
// TODO: You can modify your response body as you wish.
// Invoke the original send function.
res.send = send;
send.apply(this, arguments);
};
// Express Middleware
app.use((req, res, next) => {
// Overrides res.send
res.send = resSendInterceptor(res, res.send);
return next();
});
Your lack of code makes it really hard to answer your question, but you could use something like
Express 4.0:
router.use('/path', function (req, res) {
// Modify req
});
.use on a route will parse that before continuing on to the actual route so if somebody submitted a form or something, it will hit the .use before it goes to the .post or .get
Or you can do
Express 4.0:
app.use(function (req, res) {
// Modify Req
if (req.body.hasOwnProperty('some_form_name')) {
// Do Somthing
}
});
Which is the same thing, but it will be called before every request for every route.
Not sure if this answers your question but I think this might be what you're looking for?

Resources