My goal is to port my existing Node-Express-Pug-Mongo website onto Amazon Web Services, but I'm running into an error with rendering Pug files on Lambda. Whenever I attempt to run res.render, the page shows this: {"message": "Internal server error"} after a timeout of 3000 milliseconds (from viewing the CloudWatch console).
I've tried throwing console.log everywhere to get more information on what is causing the error, but to no avail.
res.send works with text
res.sendFile works with the Pug file that I am trying to use in the function
res.render accepts a callback input, which I have attempted to use to catch errors, but no logs exist on the console.
I've tried different ways of inputting the pug file, as you can see for the five different get URLs. All of them do the same thing.
I've tried changing to Jade, but I get the same issues.
NOTE: On a local server, the syntax in render1 and render3 are the ones that work.
ALSO: On the local server, using callbacks does cause the function to hang. I have attempted this with and without callbacks, and the issue is the same.
'use strict'
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const router = express.Router();
app.set('view engine', 'pug');
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
app.set('views', path.join(__dirname, 'views'));
router.get('/sendfile', function(req, res){
res.sendFile(__dirname+"/views/test.pug");
});
router.get('/sendtext', function(req, res){
res.send('hello!');
});
router.get('/render1', function(req, res){
res.render('test', {}, function(err){
console.log(err);
});
});
router.get('/render2', function(req, res){
res.render('.test', {}, function(err){
console.log(err);
});
});
router.get('/render3', function(req, res){
res.render('./test', {}, function(err){
console.log(err);
});
});
router.get('/render4', function(req, res){
res.render('./views/test', {}, function(err){
console.log(err);
});
});
router.get('/render5', function(req, res){
res.render(__dirname+'/views/test', {}, function(err){
console.log(err);
});
});
app.use('/', router);
// Export your express server so you can import it in the lambda function.
module.exports = app;
None of these render functions work. It always times out after 3 seconds and returns {"message": "Internal server error"}. I've tried everything I could think of. Is this an Express issue? Do I have to do something different to configure Pug? It works exactly as expected when I use the exact same module on a local Node.js server.
After a lot of digging, I figured out the issue.
My Lambda function ("server") wasn't allocated enough RAM. When I attempted to load Pug, it would overload and crash.
The default is 128MB, so turning it up to 384MB-ish worked fine.
Related
I found my question was asked a year ago here app.post() not working with Express but the code written there is outdated (the way bodyparser was added doesn't work anymore as well as function mentioned below) plus the asker never chose an answer so the question was never solved.
Here's my code
const express = require("express");
const db = require("mysql");
const app = express();
const bodyParser = require("body-parser");
const multer = require("multer"); // v1.0.5
const upload = multer(); // for parsing multipart/form-data
const http = require("http");
const path = require("path");
app.set("view engine", "jade");
app.set("views", path.join(__dirname));
console.log("before");
app.listen(8000, () => {
console.log("Server started!");
console.log("within");
});
console.log("after");
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.post("/", function(req, res) {
console.log("hit here in post");
res.render("index.jade", {});
console.log("hit here in post");
res.json({ name: "John" });
res.status(500).json({ error: "message" });
res.end();
});
app.get("/", function(req, res) {
res.render("index.jade", {});
console.log("hit here in get");
console.log(req.body);
});
Here's the output.
before
after
Server started!
within
hit here in get
{}
I even tried to wrap the app sets and uses in app.configure like the asker of the other question to see if that was the issue but that configure function doesn't seem to exist anymore because I got an error about it.
Also I should probably note. My routing here is correct. I haven't made a views subfolder yet so that's why I have it written as it is.
Update
I think I may have spotted the issue but I don't understand why it's occurring. In the network tab of the browser I see that GET is getting 404 error because of a favicon.ico request but I don't understand where that request is coming from. I've seen the serve-favicon npm module to support it but didn't want to added because I never intended to add a favicon image to my server. I don't even understand how that would work.
Reply to last comment by James
What do you mean by I configure the middleware after it has started? Are you referring to the fact that the post method is written after port listening has started? Also if that's the reason why post isn't executing how come the get method executes regardless of that? I'm not holding back any server code aside from code I currently have commented out for the moment but that code I posted is my main index.js file and it's the only file I modified from the standard npm init project. I haven't setup any routes because I don't see the need to do so (even when I add react since my project is simple in concept of communication between reactjs, nodejs and a database "hence my frustration") which is why I'm trying to have get and post only access the root directory.
favicon is automatically requested by the browser. it is the icon used in the browser tab or url address bar
Add this, before app.get():
app.all('/', function(req, res, next) {
console.log({method: req.method, url: req.url});
next();
});
I was using express route like this and I want my urls to contain query strings initially.
app.get('/', function(req, res){
res.render('index', {});
});
app.get('/us01', function(req, res){
console.log('query: '+JSON.stringify(req.query));
res.render('templates/us01', {});
});
app.get('/benchmark', function(req, res){
res.render('templates/benchmark', {});
});
However, I never get my query strings printed no matter what query strings I append after /us01. For example, "localhost:9200/us01?a=1" req.query should get me {a:1}, correct? Is this a common thing? What am I missing here?
My app.js
"use strict";
var express = require('express');
var expApp = express();
var http = require('http').Server(expApp);
var path = require('path');
var bodyParser = require('body-parser');
// all environments
expApp.set('port', process.env.PORT || 5555);
expApp.set('views', __dirname + '/views');
expApp.set('view engine', 'ejs');
expApp.use(bodyParser.urlencoded({ extended: true }));
expApp.use(bodyParser.json());
expApp.use(express.static(path.join(__dirname, 'public')));
//----------------ROUTES--------------------------//
require("./routes/route.js")(expApp);
http.listen(expApp.get('port'), function(){
console.log('Node-Server listening on port ' + expApp.get('port'));
});
My indexController.js has :
$stateProvider
.state('us01', {
url: '/us01',
templateUrl: '/us01'
}).state('benchmark', {
url: '/benchmark',
templateUrl: '/benchmark'
})....
This simple code:
const express = require('express');
const app = express();
app.get('/us01', function(req, res) {
console.log(req.query);
res.send("ok");
});
app.listen(80);
Then, accessed by http://localhost/us01?a=1 produces this output in the console:
{ a: '1' }
Or, if I use:
console.log('query: ' + JSON.stringify(req.query));
Then, I see this in the console:
query: {"a":"1"}
So, clearly something else is wrong in your code.
"localhost:9200/us01?a=1" req.query should get me {a:1}, correct?
It should get you query: {"a":"1"} if the code you show is running on port 9200 on localhost.
Is this a common thing?
No. Something other than the code you show is busted because there's nothing wrong with just that bit of code.
What am I missing here?
Things to examine:
Are you getting any output in the console when you hit any of your expected routes?
Can you prove that your server is running and your browser is hitting your route handlers?
If you just do console.log(req.query), what output do you get?
Are you absolutely sure that you've killed any prior servers and started the server that corresponds to the code you show. People sometimes get fooled by a prior version of the server that is still running and doesn't actually contain the code they think they are running.
Are you 100% sure you are running your server on the desired port that matches the port in the URL you are using.
When all else fails, sometimes a computer reboot will make sure no prior versions of anything are still running.
UPDATE 2: I just noticed that if on the app file I change the line:
app.use('/', home);
to:
app.use('/anything', home);
then all of the sub routes "roots" work fine.
UPDATE 3: I just realized something else. A method on the home.js file that I did not originally include below since I didn't think was relevant turns out to be the cause of the problem.
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
Turns out that every single sub route "root" is passing through here and since on the other routes adventureId is undefined then data is just an empty JSON object.
So the real question is: If this router bound to "/" and the other "roots" are bound to "/adventure" and "/test" why are all of them going through "/:adventrueId"?
I have a very simple ExpressJS application on which all of the "roots" in each and every single route other than home are not being handled and they always display an empty JSON object on the page.
In some posts it was mentioned that it could be a caching issue since these routes always return a 304 status, but I've tried doing an "Empty cach and hard reload" on Chrome and even with the 200 status I still get a blank page with an empty JSON object displayed on it. I tried it with MS Edge and got the exact same behavior.
Here's what I have:
On my app file
var app = express();
var home = require('./routes/home');
var adventure = require('./routes/adventure');
var test = require('./routes/test');
app.use('/', home);
app.use('/adventure', adventure);
app.use('/test', test);
On home.js file:
var express = require('express');
var router = express.Router();
router.get('/', (req, res) => {
console.log("This works fine with http://localhost:3000.");
res.render('home');
});
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
module.exports = router;
On the adventure.js file:
var express = require('express');
var router = express.Router();
router.use('/:id', (req, res) => {
console.log("This works fine with http://localhost:3000/adventure/5.");
next();
});
router.get('/:id', (req, res) => {
console.log("This works fine with http://localhost:3000/adventure/5.");
res.render('adventure');
});
//I've also tried putting this before the other routes and the result is the same.
router.get('/', (req, res) => {
console.log("This is never written in the console with http://localhost:3000/adventure.");
res.send("This is never rendered in the page.");
});
On the test.js file:
var express = require('express');
var router = express.Router();
router.use('/', (req, res) => {
console.log("This is never written on the console with http://localhost:3000/test.");
res.send("Hello from the test root route");
});
module.exports = router;
In the ExpressJS Router documentation and every single blog and example I've found it says that this is how it should work so I am really at a loss here.
Thank you.
If this router bound to "/" and the other "roots" are bound to "/adventure" and "/test" why are all of them going through "/:adventrueId"?
Because Express doesn't match routes based on which one matches best, it matches on which one matches first.
In your case, the route /:advertureId was declared before the routes for /adventure or /test. And /adventure and /test both match /:advertureId, so the handler for that route is called.
If you want to prevent this, declare more specific routes first:
app.use('/adventure', adventure);
app.use('/test', test);
app.use('/', home);
After much going around, several updates on the question and banging my head against the keyboard I finally understood what the problem is:
By having the routers set up like this:
app.use('/', home);
app.use('/adventure', adventure);
app.use('/game', gameService);
app.use('/test', test);
and on the "home" router having this method signature:
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
Every single sub route "root" was being interpreted as the parameter of the previous method so:
/adventure
/test
/anything
would be handled as:
adventrueId = adventrue
adventureId = test
adventrueId = anything
The solution was to do this:
app.use('/adventure', adventure);
app.use('/game', gameService);
app.use('/test', test);
app.use('/', home);
And now everything works.
Say for example in my node_module folder I have an npm called project which has some set defined express routes. For example,
var express = require('express');
var router = express.Router();
router.get('/', function (req, res, next) {
res.render('indexPage', {title: 'Homepage'});
});
module.exports = router;
which is kept in a routes.js file
How would this be accessed in the main node project file index.js file?
I have attempted to use require() function, however, this doesn't work.
After you set your app as an Express app then add your routes middleware(s) like the below.
Also I've added some useful code parts (a simple Express app) for any beginner:
// defining an express app
var express = require('express')
var app = express()
var server = require('http').Server(app)
// setting the express app - in case of needed
app.set('x-powered-by', false) // hide x-powered-by header!
app.set('view engine', 'ejs'); // set EJS as view engine!
app.set('views', __dirname + '/views'); // specifying the directory that contains view files
// THIS IS YOUR ANSWER PART
app.use(require('./routes'))
...
...
// Other middlewares
app.use(require('./middlewares/someMiddleware'))
// Catching 404 errors
app.use('*', function(req,res){
res.status(404).send("URL not found.")
})
// Catching and evaluating the other errors
app.use(require("./middlewares/errorHandler"))
server.listen(3001, function() {
console.log('APP Server is listening HTTP port 3001')
})
Generally the last route is been 404 error. So, if the request has not been caught in any route before 404, that means "the page cannot found".
Also, errorHandler middleware takes 4 arguments (error, request, response and next).
So, if you encountered with an error in your routes.js, and if you send this error in routes files by using next(err) this error can be caught on errorHandler middleware.
This is basic information which everyone needs when starting to develope an Express application.
For more details:
http://expressjs.com/en/guide/using-middleware.html
Good luck...
New web dev here, coming form the land of C, and everything is a little new :)
I'm working through some Express learning, and am stuck on getting POST requests to work. I'm using Advanced Rest Client on Chrome to send a POST request and am getting errors, no error number just a simple 'computer says no'.
My app.js:
var express = require('express')
, http = require('http');
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.use(express.urlencoded());
app.use(express.json());
});
app.get("/", function(req, res) {
res.send("Hello, Express!");
});
app.get("/hi", function(req, res) {
var message = "Hello :-)";
res.send(message);
});
app.get("/users/:userId", function(req, res) {
res.send("<h1>Hello user #" + req.params.userId);
});
app.post("/users", function(req, res) {
res.send("Creating a new user with name " + req.body.username);
});
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
All the other routes work, just that POST that fails.
EDIT: Additional, I'm using text/html as the content type when I post.
I've restarted the server, ensured the file is saved, rebooted the system etc. I'm guessing the issue is the parsing of the body is failing. Any help would be great, cheers.
express.json() doesn't parse text/html, so you have no req.body inside your route handler, and req.body.username line will throw an error.
I've restarted the server, ensured the file is saved, rebooted the system etc. I'm guessing the issue is the parsing of the body is failing.
Don't guess. Debug and read logs (app.use(express.logger('dev')));