Integration into existing Express application - error



  • I'm getting the following error. I have Googled my heart out and can't find an answer.

    "Refused to execute script from 'https://pharmacyinformatics.local:3000/reporting/studio/assets/studio-extensions.client.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled."

    I understand something is setting the MIME type incorrectly, but I'm unclear whether this problem originates in JSReport, or something else in my application.

    My main file is pasted below, but because there is so much in it, there might be a lot of noise, difficult for you guys to parse and help me. I'm wondering if I have something missing or in the wrong order, or if I need to set some config parameter in one of the modules I'm using. Note, I had to comment out the 'agenda' items (which were in there as a test) because it threw a bunch of errors related to MongoDB once I added the jsreports items. It was working before. TIA.

    import http             from 'http';
    import https            from 'https';
    import fs               from 'fs';
    import express          from 'express';
    import session          from 'express-session';
    import cors             from 'cors';
    import path             from 'path';
    import morgan           from 'morgan';
    import helmet           from 'helmet';
    import passport         from 'passport';
    import flash            from 'connect-flash';
    import cookieParser     from 'cookie-parser';
    import routes           from './routes';
    import { seq, Session } from './appDB'; // This only contains the admin tables, not the HL7 stuff
    import winston          from './logging/winstonConfig';
    // import Agenda           from 'agenda'; // TODO uncomment
    // import Agendash         from 'agendash'; // TODO uncomment
    
    // @TODO remove the "force: true" or set it to false for production as this DROPs all tables each time we run the app
    /**
     * Do this here so we can sync the WinstonSequelize model too
     */
    console.log('root dir', __dirname);
    seq.sync({
      force: false
    })// TODO use .then() to log a Winston entry; can't log to DB until DB is ready
    .catch(function(err) {
      throw new Error(err);
    });
    
    import { extDef }   from './model/session';
    
    let debug = require('debug')('sql-rest-api:server');
    require('./authN/passportConfig')(passport);
    let SequelizeStore = require('connect-session-sequelize')(session.Store);
    
    let app = express();
    
    // const agendaConnectionOpts = {db: {address: 'localhost:27017/agenda', collection: 'agendaJobs', options: { useNewUrlParser: true }}}; // TODO uncomment
    
    // const agenda = new Agenda(agendaConnectionOpts); // TODO uncomment
    
    const corsOptions = {
      origin: 'https://' + process.env.ORIGIN_DOMAIN, // TODO change this to whatever we use for the live site
      methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
      optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
      credentials: true // required to send cookies from browsers; didn't need this for postman
    };
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'pug');
    
    /**
     * Get port from environment and store in Express.
     */
    let port = normalizePort(process.env.PORT || '3000');// process.env.PORT is set by iisnode
    app.set('port', port);
    
    /**
     * Create HTTPS server.
     */
    if (process.env.NODE_ENV !== 'production') {
      const options = {
        key: fs.readFileSync('./src/tls/pharmacyinformatics.local.key.pem'),
        cert: fs.readFileSync('./src/tls/pharmacyinformatics.local.crt.pem')
      };
      app.server = https.createServer(options, app);
    } else {
      app.server = http.createServer(app);
    }
    
    /**
     * Setup morgan format
     */
    morgan.token('id', function (req) {
      return req.sessionID
    });
    morgan.token('statusMessage', function (req, res) {
      if (typeof req.flash === 'function' && typeof req.flash('error') !== 'undefined' && req.flash('error').length !== 0) {
        return req.flash('error').slice(-1)[0];
      } else {
        return res.statusMessage;
      }
    });
    
    
    // This format is for Morgan (HTTP) messages only; see winstonConfig for other messages' format
    // let morganFormat = ':status :statusMessage - SessionID\: :id :remote-addr ":method :url HTTP/:http-version" ":referrer" ":user-agent" ":res[content-length]"';
    let morganFormat2 = '{"status"\:":status","statusMessage"\:":statusMessage","sessionID"\:":id","remote"\:":remote-addr","method"\:":method","url"\:":url","http"\:":http-version","referrer"\:":referrer","agent"\:":user-agent","length"\:":res[content-length]"}';
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(morgan(morganFormat2, { stream: winston.stream }));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    
    // Middleware
    app.use(helmet()); // Add Helmet as a middleware
    app.use(cors(corsOptions));
    app.use(cookieParser());
    
    //=========================================================================
    //---------------------------BEGIN PASSPORT SETUP--------------------------
    //=========================================================================
    // see the express-session and connect-session-sequelize docs for parameter descriptions
    let sessParams = {
      secret: process.env.SESSION_SECRET || 'secret',// session secret; TODO replace with environment variable
      resave: false,
      saveUninitialized: false,// not sure if this should be true
      cookie: {
        domain: 'pharmacyinformatics.local', // TODO change this to whatever we use for the live site
        sameSite: 'strict',
        httpOnly: false, // if this isn't set to false, we can't read it via javascript on the client
        maxAge: 1000*60*20, // 20 minutes
        path: '/' // / is the root path of the domain
      },
      store: new SequelizeStore({
        db: seq,
        table: 'Session',
        extendDefaultFields: extDef,
        checkExpirationInterval: 0
      }),
      rolling: true, // this allows maxAge to be reset with every request, so it moves with activity
      unset: 'keep' // this is supposed to keep rows in the DB
    };
    if (app.get('env') !== 'production') { // TODO check that we only want this in dev
      // app.set('trust proxy', 1) // trust first proxy; set this is behind a proxy
      sessParams.cookie.secure = true // serve secure cookies
    }
    app.use(session(sessParams));
    app.use(passport.initialize());
    app.use(passport.session()); // persistent login sessions
    app.use(flash()); // use connect-flash for flash messages stored in session
    //=========================================================================
    //---------------------------END PASSPORT SETUP----------------------------
    //=========================================================================
    
    // API routes V1
    // app.use('/dash', ensureAuthenticated, Agendash(agenda)); // TODO use this line instead of the next one
    // app.use('/dash', Agendash(agenda)); // TODO uncomment for test
    app.use('/v1', routes);
    
    /**
     * error handler
     * error handling must be placed after all other app.use calls; https://expressjs.com/en/guide/error-handling.html
     */
    app.use(function(err, req, res, next) {
      let route = '';
      // console.log('Called second', err.message); //see catchall for what is called first
    
      // won't catch 401 Unauthorized errors. See authenticate.js for 401s
      if (!err.statusCode) err.statusCode = 500; // Sets a generic server error status code if none is part of the err
      // let data = JSON.parse(req.user.dataValues.data);
      // ${data.flash.error[0]}
      if (typeof err.route !== 'undefined') {
        route = err.route
      } else {
        route = 'Generic'
      }
    
      if (typeof req.user !== 'undefined' && req.user !== null) {
        if (typeof req.user.dataValues === 'undefined') {
          winston.error(`${err.statusCode || 500} ${err.message} - SessionID: ${req.sessionID} (${req.user.displayName})\" ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: route});
        } else {
          winston.error(`${err.statusCode || 500} ${err.message} - SessionID: ${req.user.dataValues.sid} (${req.user.dataValues.username})\" ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.dataValues.username, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: route});
        }
      } else {
        winston.error(`${err.statusCode || 500} ${err.message} - \" ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {sessionID: req.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: route});
      }
    
      if (err.shouldRedirect || err.statusCode === 500) {
        res.render('error', { error: err }) // Renders a error.html for the user
      } else {
        //The below message can be found in the catch's error.response.data item
        res.status(err.statusCode).send({"customMessage": err.message}); // If shouldRedirect is not defined in our error, sends our original err data
      }
    });
    
    // production error handler
    /*const HTTP_SERVER_ERROR = 500;
    app.use(function(err, req, res, next) {
      if (res.headersSent) {
        console.log('headers already sent');
        return next(err);
      }
    
      console.log('handling error');
      return res.status(err.status || HTTP_SERVER_ERROR).render('500');
    });*/
    
    /**
     * Listen on provided port, on all network interfaces.
     */
    const server = app.server.listen(port);
    app.server.on('error', onError);
    app.server.on('listening', onListening);
    process.on('unhandledRejection', onUnhandledRejection);
    process.on('uncaughtException', onUncaughtException);
    
    // Start JSReport
    const reportingApp = express();
    
    app.use('/reporting', reportingApp);
    
    const jsreport = require('jsreport')({
      extensions: {
        express: { app: reportingApp, server: server },
      },
      appPath: "/reporting",
      tempDirectory: "temp",
      configFile: __dirname + "/jsrconfig/jsreport.config.json"
    });
    
    jsreport.init().then(() => {
      console.log('jsreport server started')
    }).catch((e) => {
      console.error(e);
    });
    // End JSReport
    
    async function graceful() {
      // await agenda.stop(); // TODO uncomment
    }
    
    process.on('SIGINT', graceful);
    
    /**
     * Normalize a port into a number, string, or false.
     * @param {string} val - The port, input as a string to be parsed as an integer.
     * @return Return the original val if no integer can be parsed; return integer port number if val was parsable; otherwise return false.
     */
    function normalizePort(val) {
      let port = parseInt(val, 10);
    
      if (isNaN(port)) {
        // named pipe
        return val;
      }
    
      if (port >= 0) {
        // port number
        return port;
      }
    
      return false;
    }
    
    function onUnhandledRejection(error) {
      // Will print "unhandledRejection err is not defined"
      console.log('unhandledRejection', error.message);
    }
    
    function onUncaughtException(error) {
      console.log('unhandledException', error.message);
    }
    
    /**
     * Event listener for HTTP server "error" event.
     * @param {Error} error - An error object.
     */
    function onError(error) {
      console.log('onError');
      if (error.syscall !== 'listen') {
        throw error;
      }
    
      let bind = typeof port === 'string'
        ? 'Pipe ' + port
        : 'Port ' + port;
    
      // adding this line to include winston logging
      //winston.error(`${err.status || 500} - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`);
    
      // handle specific listen errors with friendly messages
      switch (error.code) {
        case 'EACCES':
          console.error(bind + ' requires elevated privileges');
          process.exit(1);
          break;
        case 'EADDRINUSE':
          console.error(bind + ' is already in use');
          process.exit(1);
          break;
        default:
          throw error;
      }
    }
    
    /**
     * Event listener for HTTP server "listening" event.
     */
    function onListening() {
      let addr = app.server.address();
      let bind = typeof addr === 'string'
        ? 'pipe ' + addr
        : 'port ' + addr.port;
      // the following probably won't get to the DB because it isn't online when it is called
      // winston.info('Listening on ' + bind, {sessionID: 'SYSTEM', username: 'SYSTEM', ip: addr});
      console.log('Listening on ' + bind);
    }
    
    export {
      app,
      // agenda,
      jsreport
    };
    




  • I found it after I posted here. Thanks!



  • This post is deleted!


  • I ended up reverting to the previous version, which worked, but gave me another error. To get rid of the new error,
    I changed this:

    app.use(express.urlencoded({ extended: false }));
    

    To this:

    app.use(express.urlencoded({ extended: true }));
    

Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.