I have an Express.js/Node.js website hosted with Heroku. If a file can't be found, the server is supposed to send a 404 error (like most websites do). But the error handlers in my code don't work properly. When the client requests a file that doesn't exist, the page will load...and load...and load...forever. How do I make the server stop loading when it detects the file can't be found?
This is the first section of my JavaScript:
var express = require('express'); // Express.js
var app = express();
var http = require('http');
var server = http.createServer(app);
var bodyParser = require('body-parser');
var postgres = require('pg'); // Postgres database
app.use(express.static('static', {
extensions: ['html']
}));
app.all('*', function (request, response, next) {
var redirectURL = request.query.redirect;
if (redirectURL != undefined) {
response.redirect(redirectURL);
}
});
app.get('/', function (request, response, next) {
response.redirect('/main/index');
});
And the following is my error handling middleware (it goes right after the previous part). The first one handles 400x error codes and the second one handles 500x error codes.
// Handle 404 error
app.use(function(request, response) {
response.status(400);
response.send("Error 404!");
});
// Handle 500 error
app.use(function(error, request, response, next) {
response.status(500);
response.send("Error 500!");
});
server.listen(process.env.PORT || 8080, function () {
console.log('Listening on port 8080!');
});
Call response.end() in your middleware, like so
// Handle 404 error
app.use(function(request, response) {
response.status(400);
response.send("Error 404!");
response.end();
});
This is how I check for errors in my app, one single middleware
app.use((err, req, res, next) => {
if (err.statusCode === 403) {
res.statusCode = 403;
var out = {
message: 'missing/invalid authorization: ' + err.message,
code: err.code,
statusCode: err.statusCode
};
res.end(JSON.stringify(out));
return;
}
next(err);
});
Check that your middleware actually gets called, console.log should be sufficient
If a middleware does not end the request, it must forward the request to the next middleware, so you need to call next(), the format of a middleware is
app.use((req, res, next) => {
//I'm not doing anything, forward the request
next();
});
app.use((req, res, next) => {
req.send('I ended the request');
//this middleware ended the request
}));
I had almost the same issue (in my case it was the page for HTTP 500 that was loading forever) and the problem was with another middleware that I have added myself and which was before the error handler middlewares and inside which I forgot to call next():
app.use(function(req: Request, res: Response, next: NextFunction) {
closeConnFromRequestStorage()
next(); // make sure to call to call next
});
Related
I have my node.js restify server, and folder with static resource
const restify = require('restify')
let server = restify.createServer()
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url)
});
server.get('/*', restify.plugins.serveStatic({
directory: __dirname + '/static',
default: 'index.html'
}));
i'm trying to understand how to make get request to index.html with parameters like localhost:8080/index.html?token=123
and if token is valid, return index.html to client, else return error
You can chain multiple request handlers and the next() method - first do some parameters' validation and then, as a second handler, use the serveStatic method. Here's an example:
const restify = require('restify')
let server = restify.createServer()
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url)
});
server.get('/*', (request, response, next) => {
const token = request.query.token;
if(token !== '123') {
//those two lines below will stop your chain and just return 400 HTTP code with some message in JSON
response.send(400, {message: "Wrong token"});
next(false);
return;
}
next(); //this will jump to the second handler and serve your static file
return;
},
restify.plugins.serveStatic({
directory: __dirname + '/static',
default: 'index.html'
}));
I need to block every IP address from accessing my site except one or two IP's provided by myself. I have tried many modules but nothing seems to work.
var express = require('express')
var AccessControl = require('express-ip-access-control');
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var middleware = AccessControl(options);
app.use(AccessControl(options));
var options = {
mode: 'deny',
denys: [],
allows: ['**8.1**.1.**'],
forceConnectionAddress: false,
log: function(clientIp, access) {
console.log(clientIp + (access ? ' accessed.' : ' denied.'));
},
statusCode: 401,
redirectTo: '',
message: 'Unauthorized'
};
app.listen(3000, function () {
console.log(' app listening on port 3000!')
})
on running and accessing my site from my above code i am getting the console message as
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
any help?
You can simply add your own middleware that checks the IPs, no need to include another module.
You can see the ip from the request with req.connection.remoteAddress.
Before you define your routes, add something like this:
// Custom Middleware
app.use((req, res, next) => {
let validIps = ['::12', '127.0.0.1']; // Put your IP whitelist in this array
if(validIps.includes(req.connection.remoteAddress)){
// IP is ok, so go on
console.log("IP ok");
next();
}
else{
// Invalid ip
console.log("Bad IP: " + req.connection.remoteAddress);
const err = new Error("Bad IP: " + req.connection.remoteAddress);
next(err);
}
})
This will throw an error if an invalid ip comes in. Below all your routes, add something like this:
// Error handler
app.use((err, req, res, next) => {
console.log('Error handler', err);
res.status(err.status || 500);
res.send("Something broke");
});
You need to define your options before you use them. Otherwise, you're passing in undefined to app.use(AccessControl(options)).
Not sure how this is compiling for you, but adding the following line to the top of your script might help show a few more errors that would help.
'use strict';
Secondly, according to the express-ip-access-control documentation:
'allow' mode (Whilelist):
Deny by default, only allow IPs in the whitelist (allows) and not excluded by the blacklist (denys).
So change options.mode from 'deny' to 'allow'.
I have this script with which I'm trying to POST, GET and DELETE some stuff.
When I try POST or GET, the right messages are logged, but when I try DELETE, I get the following error:
Cannot GET /del_user
The URL I'm using is http://127.0.0.1:8081/del_user
What can be wrong in here?
var express = require('express');
var app = express();
// This responds with "Hello World" on the homepage
app.get('/', function (req, res) {
console.log("Got a GET request for the homepage");
res.send('Hello GET');
})
// This responds a POST request for the homepage
app.post('/', function (req, res) {
console.log("Got a POST request for the homepage");
res.send('Hello POST');
})
// This responds a DELETE request for the /del_user page.
app.delete('/del_user', function (req, res) {
console.log("Got a DELETE request for /del_user");
res.send('Hello DELETE');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
console.log("Got a GET request for /list_user");
res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
console.log("Got a GET request for /ab*cd");
res.send('Page Pattern Match');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I solved it by changing the app.delete to app.get and then placing the required remove statement inside the app.get. Something like this :-
app.get('/delete/:userId', (req, res) => {
Users.remove({ _id: req.params.userId }, (error, posts) => {
if (error) {
console.warn(error);
}
else {
data = posts
res.render("delete", {"data": data})
}
});
});
In your code you're binding the /del_user URL to the HTTP DELETE method.
So all you need to do is specify the DELETE method in your application or in Postman.
If you're not using it, it's an App in Google Chrome and you might want to download it, it makes your life a LOT easier ;)
Also, since the HTTP method is already declared to be DELETE, there is no need to specify it in the URL.
This is part of the RESTful working.
If you are using AJAX to try your code, you need to specify the method, which is delete.
$.ajax({
url: "http://127.0.0.1:8081/del_user",
type: "DELETE"
});
I'm developing a rest server on Node JS with Express.
I'm trying to wrap all my endpoints in try\catch block, so a central point of error will response back to the sender with details.
My problem that response (res instance) is alive for each of the endpoints methods, but I don't know how to make it global.
try {
app.get('/webhook', function (req, res) {
webhook.register(req, res);
});
app.get('/send', function (req, res) {
sendAutoMessage('1004426036330995');
});
app.post('/webhook/subscribe', function (req, res) {
webhook.subscribe("test");
});
app.post('/webhook/unsubscribe', function (req, res) {
webhook.unsubscribe("test");
});
} catch (error) {
//response to user with 403 error and details
}
There is a library (express-async-errors) which could suit your needs.
This enables you to write async route handlers without wrapping the statements in try/catch blocks and catch them with global error handler.
To make this work you must:
1. Install the express-async-errors package
2. Import package (before the routes)
3. Set up global express error handler
4. Write async route handlers (More info about this)
Example usage:
import express from 'express';
import 'express-async-errors';
const app = express();
// route handlers must be async
app.get('/webhook', async (req, res) => {
webhook.register(req, res);
});
app.get('/send', async (req, res) => {
sendAutoMessage('1004426036330995');
});
app.post('/webhook/subscribe', async (req, res) => {
webhook.subscribe("test");
});
app.post('/webhook/unsubscribe', async (req, res) => {
webhook.unsubscribe("test");
});
// Global error handler - route handlers/middlewares which throw end up here
app.use((err, req, res, next) => {
// response to user with 403 error and details
});
try catch can not catch error asynchronously.
This will work:
app.get('/webhook', function (req, res) {
try {
//enter code here
} catch (error) {
// something here
}
});
But it is local and not the best way.
Good way is make error-handling middleware function. It is global. You need to define it after all app.use() and routes calls.
app.use(function(err, req, res, next) {
// This is error handler
});
You can send the html page with details of error to client as usual.
Also, by default, Express have built-in error handler. The error will be written to the client with stack trace (It does not work in production mode).
this kind of try catch will not catch errors when some third function is called do the best solution will use global exception handler
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.end();
});
also you have to use promises in your end point handlers
that will catch errors in any scope
I'm new to Express and trying to use middleware to handle a POST request. If I expose the endpoint, and make a request to the API, everything works fine.
Working Correctly
api/index.js
app.post('/api/endpoint', (req, res, next) => {
next();
});
server.js
app.use(function() {
console.log('hello'); // => hello
});
But when I try to replace the middleware function with a module that exports a function, the function never gets invoked.
Not Working
api/index.js
app.post('/api/endpoint', (req, res, next) => {
next();
});
server.js
const makeExternalRequest = require('./server/makeExternalRequest');
...
console.log(makeExternalRequest, typeof makeExternalRequest);
// => [Function] 'function'
app.use(makeExternalRequest);
server/makeExternalRequest.js
module.exports = function(err, req, res, next) {
console.log('hello', err);
}
The function in server/makeExternalRequest.js is never invoked, and nothing logs... Am I using app.use(...) incorrectly?
Express middleware requires three arguments, the third of which is a function you call when you're done to move the request along to the next handler:
module.exports = function (req, res, next) {
console.log('hello');
next();
};
Without calling the third parameter, your request will just remain pending and a response will never be sent. Also, be sure you call app.use before any handler that would return the response. If the response is sent first, then your middleware will never be reached.