Cannot GET when using forever with node and express - node.js

We are using NodeJS and Express in combination with forever. That worked fine, but now we had to update our NodeJS version and it all stops working.
We use angular with ui-routing for frontend routing so we have an static folder.
I can go to our homepage (/) and from there I can navigate to the whole site. But when I refresh an page or I go directly to an page (eg. /products) I get an
Cannot GET /products
error.
Node gives an 404 error.
When I run the script directly without forever everything works fine. As you can see we have 2 static folders configured in express. Before the update everything works fine.
We also use Apache to redirect custom domainnames to specific pages without changing the address in the browser, but that works fine (only shows the GET error instead of the page).
Anybody any idea how to solve this?
our app.js
var path = require('path');
var fs = require('fs');
// Return values from different config files will be added to this object so you can call config.[category].[property].
config = {};
// Save the app root directory to a global variable so it can be used in config files and other parts of the app. global.root is reserved, but global.path.root can be used without problems.
global.path = {root: path.resolve(__dirname)};
// Set environment and initialize environment-specific config variables
config.env = require(path.join(__dirname, 'config', 'env.config'));
// Set up database connection to use throughout the application
config.db = require(path.join(__dirname, 'config', 'db.config'));
// HTTP for development environment, HTTPS for production environment
var http = require('http');
var https = require('https');
// Set up debugging/logging for the development environment
var debug = require('debug')('http');
// Start the app using the Express settings/routines in express.config.
var app = require(path.join(__dirname, 'config', 'express.config'));
// Start GraphQL process
// require(path.join(__dirname, 'config', 'graphql.config'))(app);
var router = require(path.join(__dirname, 'config', 'routes.config'));
router(app);
// Running in production mode: HTTPS only
if(config.env.name === 'production') {
var credentials = {
privateKey: fs.readFileSync('privkey'),
certificate: fs.readFileSync('fullchain')
};
var server = https.createServer(credentials, app);
server.listen(4443);
server.on('error', onError);
server.on('listening', onListen);
var server2 = http.createServer(app);
server2.listen(8080);
// Running in development mode: HTTP only
} else {
var server = http.createServer(app);
server.listen(config.env.port);
server.on('error', onError);
server.on('listening', onListen);
}
//some listeners here
Our express.config.js
var path = require('path');
console.log('Initializing API...');
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var compression = require('compression');
var morgan = require('morgan');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var config = require(path.join(__dirname, 'db.config'));
// The GraphQL server implementation for Express by the Apollo team.
var graphqlExpress = require('graphql-server-express').graphqlExpress;
var graphiqlExpress = require('graphql-server-express').graphiqlExpress;
var OpticsAgent = require("optics-agent");
var passport = require('passport');
var app = express();
// Handle application/json requests
app.use(bodyParser.json({ limit: '50mb' }));
// Handle application/x-www-form-urlencoded requests (usually POST, PUT, etc.)
app.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));
app.use(cookieParser());
app.use(session({
store: new MongoStore({
url: 'mongodb://' + config.url + ':' + config.port + '/' + config.name
}),
secret: 'secret',
key: 'skey.sid',
resave: false,
saveUninitialized: false,
cookie : {
maxAge: 604800000 // 7 days in miliseconds
}
}));
app.use(passport.initialize());
app.use(passport.session());
require(path.join(__dirname, 'auth.config'))(passport); //Load passport config
app.use(function(req, res, next) {
req.resources = req.resources || {};
// res.locals.app = config.app;
res.locals.currentUser = req.user;
res.locals._t = function (value) { return value; };
res.locals._s = function (obj) { return JSON.stringify(obj); };
next();
})
// Use gzip compression (following the Express.js best practices for performance)
app.use(compression());
// Serve frontend and static files like stylesheets and images from the Express server
app.use(express.static(path.join(__dirname, '..', '..', 'app')));
app.use(express.static(path.join(__dirname, '..', '..', 'public')));
// Morgan logger (previously named express-logger)
app.use(morgan("dev"));
// Generate the GraphQL schema
var schema = require(path.join(__dirname, 'graphql.config'))().then(function(schema) {
/* Use Apollo Optics middleware for query optimization/tracing. */
OpticsAgent.instrumentSchema(schema);
app.use('/apiv2', OpticsAgent.middleware());
console.log('GraphQL schema generated.');
/* Return params object for Apollo GraphQL Server using a request handler function. */
app.use('/apiv2', graphqlExpress(function(req) {
return {
schema: schema,
debug: true,
context: {
opticsContext: OpticsAgent.context(req)
}
};
}));
app.use('/graphiql', graphiqlExpress({endpointURL: '/apiv2'}));
console.log('GraphQL started.');
/* Handle all other HTTP requests AFTER graphql server API endpoint and other routes are defined. */
app.use('*', express.static('app'));
});
// Always keep the errorHandler at the bottom of the middleware function stack!
// Returns a user-friendly error message when the server fails to fulfill the request
app.use(function(err, req, res, next) {
var status = 500, response = {message: 'An internal server error has occurred while trying to load this page. '};
console.error(err.stack);
res.status(status).json(response);
next(err);
});
module.exports = app;

Not really an solution to this problem, but we changed forever to PM2 (https://github.com/Unitech/pm2) and that program is doing his job fine!

Related

Angular front end not getting appropriate response for http request from express backend

I'm using Angular 7 to send a http request to an Express 4 backend code, but keep getting a 404 response in return. I think it might be an issue with the way I've listed the path for the http request, but not sure. This is the first time I'm attempting something like this. I have set up a proxy.conf.js file in Angular to allow from cross origin communication (angular runs on localhost:4200, express on localhost:8085). My Express code is saved under C:/ABC/myapp. Here's the relevant code:
Angular proxy.conf.js file:
{
"/": {
"target": "http://localhost:8085",
"secure": false,
"logLevel": "debug"
}
}
Angular service code which sends the http request:
export class ContactUsService {
private url = '/contactus';
private result: any;
message: string;
addMessage(contactUsMessage: contactUsInterface): Observable<contactUsInterface> {
return this.http.post<contactUsInterface>(this.url, contactUsMessage). (retry(3));
};
constructor(private http: HttpClient) {}
};
Express app.js code:
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var createError = require('http-errors');
var express = require('express');
var logger = require('morgan');
var mongoose = require('mongoose');
var path = require('path');
var winston = require('winston');
var contactUsRouter = require(path.join(__dirname, 'routes', 'contactUs'));
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/contactus', contactUsRouter);
app.use(function(req, res, next) {
next(createError(404));
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
contactUs.js code (for contactUsRouter):
var express = require('express');
var router = express.Router();
var contactUsMessage = require('../models/contactUsMessage');
router.route('/contactus')
.get(function(req,res,next){
res.send("Hello")
})
.put(function(req,res,next){
res.send("Hello")
});
module.exports = router;
When I reach the contactus page (url: localhost:4200/contactus) and execute the submit button for the form, I get the following errors:
In the browser console: "HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier).
(XHR)POST - http://localhost:4200/contactus"
In the npm log: "POST /contactus 404 3.081 ms - 2128
Error: Failed to lookup view "error" in views directory "C:\ABC\myapp\views".
Any words of wisdom on what I'm doing incorrectly?
Currently you are exposing a route of POST /contactus/contactus because you are specifying a base route with the statement app.use('/contactus', contactUsRouter);, then adding/appending an additional/extra /contactus with the registration of the POST/PUT routes.
Try change the POST route to path to just '/':
var express = require('express');
var router = express.Router();
var contactUsMessage = require('../models/contactUsMessage');
router.route('/')
.get(function(req,res,next){
res.send("Hello")
})
.post(function(req,res,next){
res.send("Hello")
});
module.exports = router;
Hopefully that helps!
Your proxy conf file is not working properly.
The requests are still trying to look for a POST method route /contactus in angular application running on port 4200 ((XHR)POST - http://localhost:4200/contactus) which does not exist and hence you are getting a 404.
Make sure you have followed the steps mentioned on official angular website - Add Proxy for backend server - angular.io
It will be advisable if you use proxy path /api instead of / . Something like this
{
"/api": {
"target": "http://localhost:8085",
"secure": false
}
}
Hope it helps

Socket.io connecting many times instead of just once

I have build this app, with express.js, its a basic webapp, but now i want to add a simple messaging system.
I already had built my express app and server like this:
const app = require('./app');
app.set('port', process.env.PORT || 7777);
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
But as I follow this tutorial on socket.io: https://socket.io/get-started/chat/
I changed my start.js to this, to use socket.io:
const app = require('./app');
app.set('port', process.env.PORT || 7777);
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
const io = require('socket.io').listen(server);
io.on('connection', function(socket){
console.log('a user connected');
});
It says on the tutorial that when a user signs up i should see a console log saying: a user is connected
However I get one log per frame... not just one per connected user.
Is this behaviour correct with the changes i made.. or should i still be getting still just one log per connected user?
Im also using pug as my templating language, and i have, at the end of my layout file this:
block scripts
script(src=`https://maps.googleapis.com/maps/api/js?key=${process.env.MAP_KEY}&libraries=places`)
script(src="/dist/App.bundle.js")
script(src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js")
script.
const socket = io()
App.js:
const express = require('express');
const session = require('express-session');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);
const path = require('path');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const passport = require('passport');
const promisify = require('es6-promisify');
const flash = require('connect-flash');
const expressValidator = require('express-validator');
const routes = require('./routes/index');
const helpers = require('./helpers');
const errorHandlers = require('./handlers/errorHandlers');
require('./handlers/passport');
// create our Express app
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views')); // this is the folder where we keep our pug files
app.set('view engine', 'pug'); // we use the engine pug, mustache or EJS work great too
// serves up static files from the public folder. Anything in public/ will just be served up as the file it is
app.use(express.static(path.join(__dirname, 'public')));
// Takes the raw requests and turns them into usable properties on req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Exposes a bunch of methods for validating data. Used heavily on userController.validateRegister
app.use(expressValidator());
// populates req.cookies with any cookies that came along with the request
app.use(cookieParser());
// Sessions allow us to store data on visitors from request to request
// This keeps users logged in and allows us to send flash messages
app.use(session({
secret: process.env.SECRET,
key: process.env.KEY,
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
// // Passport JS is what we use to handle our logins
app.use(passport.initialize());
app.use(passport.session());
// // The flash middleware let's us use req.flash('error', 'Shit!'), which will then pass that message to the next page the user requests
app.use(flash());
// pass variables to our templates + all requests
app.use((req, res, next) => {
res.locals.h = helpers;
res.locals.flashes = req.flash();
res.locals.user = req.user || null;
res.locals.currentPath = req.path;
next();
});
// promisify some callback based APIs
app.use((req, res, next) => {
req.login = promisify(req.login, req);
next();
});
// After allllll that above middleware, we finally handle our own routes!
app.use('/', routes);
// If that above routes didnt work, we 404 them and forward to error handler
app.use(errorHandlers.notFound);
// One of our error handlers will see if these errors are just validation errors
app.use(errorHandlers.flashValidationErrors);
// Otherwise this was a really bad error we didn't expect! Shoot eh
if (app.get('env') === 'development') {
/* Development Error Handler - Prints stack trace */
app.use(errorHandlers.developmentErrors);
}
// production error handler
app.use(errorHandlers.productionErrors);
// done! we export it so we can start the site in start.js
module.exports = app;
The problem was that i had opened multiple tabs with the app, therefore all the logs where from other tabs being connected.

receiving 404 not found when calling axios with node and heroku

my react app landing page calls and axios.get on component did mount. I have no issues when running my page locally, however when I deploy with heroku, my axios call returns "404 not found nginx". It feels like a simple fix, although I cant seem to find any threads online that apply to my issue. my server.js is configured as follows
const express = require("express");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const routes = require('./routes');
const dotenv = require("dotenv");
var request = require('request'); // "Request" library
var cors = require('cors');
var querystring = require('querystring');
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var morgan = require('morgan');
// var configDB = require('./config/database.js');
require('./config/passport')(passport); // pass passport for configuration
// const fs = require("fs");
var client_id = process.env.DB_SPOTIFY_CLIENT_ID; // Your client id
var client_secret = process.env.DB_SPOTIFY_CLIENT_SECRET; // Your secret
var redirect_uri = process.env.DB_REDIRECT_URI; // Your redirect uri
dotenv.config();
// const port = process.env.PORT || 3030;
const port = 3030
const app = express();
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: 'ilovescotchscotchyscotchscotch' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
// Demo middleware to play with error handling
app.use((req, res, next) => {
const startTime = Date.now();
console.log("Request Time: " + startTime);
console.log(`${req.method} ${req.path}`);
// Request returns 500, default handler returns error
// as html with stack trace in dev, does not terminate server process.
//throw new Error("Bazinga!");
next();
// Request returns 500, default handler returns error as html showing stack trace,
// and terminates server process with error ERR_HTTP_HEADERS_SENT.
//next(new Error("Bazonga!"));
const endTime = Date.now();
console.log(
"Response Time: " + endTime + " Elapsed: " + (endTime - startTime)
);
// Request goes through, error is written to log.
//throw new Error("Bazunga!");
});
// app.use("/node-api/server.js/schedule", (req, res, next) => {
// fs.readFile("data/schedule.json", (err, data) => {
// if (err) {
// // If err, then
// next(err);
// } else {
// res.type("json").send(data);
// }
// });
// });
// routes ======================================================================
require('./routes/LoginRegister.Routes')(app, passport); // load our routes and pass in our app and fully configured passport
app.use("/serverSideStuff/server.js", routes);
app.use((req, res) => {
res.status(404).send("<h2>The path is not valid</h2>");
});
app.listen(port, () => {
console.log(`Magic happens on port ${port}`);
});
you forgot to uncomment this line:
// const port = process.env.PORT || 3030;
and delete this one:
const port = 3030
process.env.PORT will be heroku port :)

Executing a Node.js script to send a Twilio message from a client side button click

I am looking to have a button on my web application query a MongoDB and send out a text message to the appropriate individuals based on the result of that query.
The issue I am having is in testing. I can't figure out a way to have the button on the client side run the node.js file on the server side.
Node.js: v8.9.4
Vue.js: 2.5.13
Express: 4.13.3
EDIT:
I've been able to get the nodejs script to run on its own. I just don't know how to call it from the client side
EDIT 2:
Main.js
// Dependencies
var http = require('http');
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
var cors = require('cors');
var mongoose = require('mongoose');
// Configuration
var config = require('./config');
var twilio = require('twilio');
// Database
mongoose.connect(config.database);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function(){
console.log('Connected to database');
});
var app = express();
app.set('port', process.env.PORT || 3000);
// Setup middleware
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser(config.sessionSecret));
app.use(express.static(path.join(__dirname, 'dist')));
app.use(busboy());
app.use(cors({
origin: true,
credentials: true
}));
app.get('/session',function(req){
twilio.notifyOnSession();
});
var server = http.createServer(app);
var port = app.get('port');
server.listen(port);
console.log('Listening on port ' + port);
// Load server router
require('./router')(app);
EDIT 3:
Dashboard.vue
Here is the code that is already in place to redirect to the correct part of the app
getHelpNext() {
var topic = this.pickedTopic;
topic = topic.toLowerCase();
var linkName = '/session/' + topic;
this.$router.push(linkName);
}
EDIT 4:
Router.js
var path = require('path');
module.exports = function(app){
console.log('Initializing server routing');
require('./auth')(app);
require('./api')(app);
// Determine if incoming request is a static asset
var isStaticReq = function(req){
return ['/auth', '/api', '/js', '/css'].some(function(whitelist){
return req.url.substr(0, whitelist.length) === whitelist;
});
};
// Single page app routing
app.use(function(req, res, next){
if (isStaticReq(req)){
return next();
}
res.sendFile(path.join(__dirname, '../dist/index.html'));
});
};
You need to make an endpoint that will get the request. This goes in express:
app.post('/some/end/point', (req, res) => {
// -> send twillo message code here. If you use bodyParser,
// req.body.message holds 'foo bar'
res.status(200).end(); // do this if sending the message is a success
})
where app is your express server that listens on some port.
And this should go in your vue
this.$http.post('/some/end/point', {
message: 'foo bar'
})
You are describing here several components that should be unit tested separately.
Query Mongodb
Node JS script - with mock of mongodb query result and not.
Twillo text sending.
UI test
Your question is probably referring to the last part but in order to properly implement it, you must break the unit test to these following topics.
As for UI test, there are many tools , my favourite is puppeteer.
You need to create an endpoint on your server using expressjs, expose it to the internet and then call it from your client by doing a request.

Express Session Does Not Save After Redirect

In my production app, saving data to a session then redirecting is completely unreliable. A console.log after saving the session shows the data has been attached. Then on redirect, another console.log shows that the session has been reset. Every 3-5 tries, the session will persist across the redirect, but it is mostly unreliable. In my development app this code works flawlessly...
• I've tried changing the version of express-session
• I've tried moving the static folder above the session middleware in server.js
• I've tried using req.session.save()
UPDATE ******
This is a known issue with the session middleware: https://github.com/expressjs/session/pull/69
Here is my server.js
// Module Dependencies
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var session = require('express-session');
var favicon = require('serve-favicon');
var methodOverride = require('method-override');
// Set Environment from ENV variable or default to development
var env = process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var config = require('./config/config');
// Set Port
var port = process.env.PORT || config.app.port;
// Connect to our MongoDB Database
// mongoose.connect(config.db);
// set the static files location /public/img will be /img for users
app.use(express.static(__dirname + '/public'));
// Express Session
app.use(session({
secret: 'asfasfa3asfa',
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: 2160000000
}
}));
// Favicon
app.use(favicon(__dirname + '/public/img/favicon.ico'));
// Set Jade as the template engine
app.set('views', './app/views');
app.set('view engine', 'jade');
// Get req.body as JSON when receiving POST requests
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({
type: 'application/vnd.api+json'
})); // parse application/vnd.api+json as json
app.use(bodyParser.urlencoded({
extended: true
})); // parse application/x-www-form-urlencoded
// override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
app.use(methodOverride('X-HTTP-Method-Override'));
// routes ==================================================
require('./app/routes')(app); // pass our application into our routes
// start app ===============================================
app.listen(port);
console.log('****** App is now running on port ' + port + ' ******'); // shoutout to the user
exports = module.exports = app; // expose app
Here is the controller where the session is being saved:
// Module dependencies.
var config = require('../../config/config');
// Render Either Home Page or Dashboard Page If User is Logged In
var index = function(req, res) {
console.log("Session At Home Page: ", req.session)
if (req.session.user) {
res.render('dashboard');
} else {
res.render('home');
}
};
// Handle Authentication Callback
var callback = function(req, res) {
// Get Access Token via Service-SDK
Service.getAccessToken(req, function(error, tokens) {
if (error) {
console.log(error);
return res.redirect('/');
}
// Otherwise, Save User Data & API Tokens To Session
req.session.regenerate(function(err) {
req.session.user = tokens.user_id;
req.session.access_token = tokens.access_token;
req.session.client_token = tokens.client_token;
req.session.save(function(err) {
console.log("Session Before Redirect: ", req.session);
res.redirect('/');
})
});
});
};
module.exports = {
index: index,
callback: callback
};
My Routes
app.get('/auth/service/callback', application.callback)
app.get('/logout', application.logout);
app.get('/', application.index);
There is a conflict between the livereload and the express-session in the Express 4. You can read more about it here https://github.com/expressjs/cookie-session/issues/14
But in short, the livereload must be called AFTER the session. As this:
var express = require("express");
var http = require("http");
var session = require("express-session");
var livereload = require("connect-livereload");
var app = express();
app.set("port", 9090);
/**
* First you must config the session
*/
app.use(session({
secret: "keyboardcat",
name: "mycookie",
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: 6000000
}
}));
/**
* Then you can config the livereload
*/
app.use(livereload())
/**
* This simple url should create the cookie.
* If you call the livereload first, the cookie is not created.
*/
app.get("/",function(req,res){
req.session.name = "blaine";
res.end("ok");
});
/**
* If you call the livereload first, the session will always return nothing
* because there is no cookie in the client
*/
app.get("/me",function(req,res){
var name = req.session.name;
var message = "Hello [" + name + "]!";
res.end(message);
});
http.createServer( app ).listen(
app.get("port"),
function(){
console.log("server is running in port ", app.get("port"));
}
)
If you call the livereload BEFORE the session config, all will seems to work but the cookie will not persist. This was a tricky bug and I lost a full day into it. I hope this help somebody.

Resources