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 };
-
Here you find the details
https://github.com/jsreport/jsreport-studio/issues/44
-
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 }));