Search code examples
node.jsexpressforever

Cannot GET when using forever with node and express


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;

Solution

  • 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!