Nodejs的Express和CORS在这么多呼叫后挂起



所以我有一个Node.JS REST API,我在其中添加了CORS npm模块。现在我发现,在我调用了这么多之后,服务器会挂起,我必须重新启动它。而且调用的次数也很少,比如6或7次。我尝试使用默认设置的CORS npm模块,我也尝试手动设置,如下所示:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
})

但无论我用哪种方式,结果都是一样的。任何想法都将不胜感激。

这是我的main.js文件的代码

// Imports
var express  = require('express'),
    CORS = require('cors'),
    app = express(),                               // create our app w/ express
    verRouter = express.Router(),                  // Create router for version stuff
    stageRouter = express.Router(),                // Create router for version stuff
    morgan = require('morgan'),                    // log requests to the console (express4)
    bodyParser = require('body-parser'),           // pull information from HTML POST (express4)
    methodOverride = require('method-override'),   // simulate DELETE and PUT (express4)
    winston = require('winston'),                  // logging library
    mysql = require('mysql'),                      // mysql library
    jwt = require('jsonwebtoken'),                 // library to create JSON tokens for authentication
    passport = require('passport'),                // Authentication library
    LdapStrategy = require('passport-ldapauth'),   // specific library for LDAP use
    config = require('./config/config')            // config to hold sensitive info like mysql credentials and secret key
//init logger
var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)(),
    new (winston.transports.File)({ filename: 'versions_api.log' })
  ]
})
logger.level = 'debug'
logger.exitOnError = false
//LDAP Authentication
var eaOPTS = {
  server: {
    url: config.ldap.url,
    bindDn: config.ldap.bindDn,
    bindCredentials: config.ldap.bindCredentials,
    searchBase: config.ldap.searchBase,
    searchFilter: config.ldap.searchFilter,
    groupSearchBase: config.ldap.groupSearchBase,
    groupSearchFilter: config.ldap.groupSearchFilter,
    groupSearchAttributes: config.ldap.groupSearchAttributes
  }
}
passport.use(new LdapStrategy(eaOPTS))
// db configuration
var pool = mysql.createPool({
  connectionLimit : 10,
  host            : config.db.host,
  user            : config.db.user,
  password        : config.db.password,
  database        : config.db.database
})
app.use(CORS(corsOpts))
app.use(morgan('dev'))                                          // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}))             // parse application/x-www-form-urlencoded
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(methodOverride())
//Import the routes
var versions = require('./routes/versions')(app, pool, logger, express, jwt)
var states = require('./routes/states')(app, pool, logger, express, jwt)
var auth = require('./routes/auth')(app, logger, express, passport, jwt)
//Set up the routes
app.use('/versions', versions)
app.use('/states', states)
app.use('/auth', auth)
//Catch any 404s and print out their error message.
app.use(function(err, req, res, next) {
  if(err.status !== 404) {
    return next()
  }
  res.status(404)
  logger.error(err.message)
  console.log(err.message)
  res.send(err.message)
})
// listen (start app with nodemon main.js)
var port = process.env.PORT || 8888
app.listen(port, function() {
  console.log("App listening on port "+port)
})

谢谢!

更新:根据请求,以下是versions.js和state.js文件:

/*************************************************************************************
VERSIONS.JS
Description: Module holding all routes for the versions section of the Version REST
            API. All functions in this module handle the versions. Add a new version,
            get all versions, get a single version, update a version, search versions.
*************************************************************************************/
module.exports = function(app, pool, logger, express, jwt) {
  var helper = require("../modules/helpers")(logger)
  var router = express.Router()
  // get all versions
  router.get('/list', function(req, res, next) {
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT *, DATE_FORMAT(st.launch_date, '%Y-%m-%d %H:%i:%s') AS launch FROM versions v LEFT JOIN state_transition st ON (st.version_id=v.id)", function(err, vers) {
        if (err) return helper.handleErr(err, res)
        res.json(vers) // return all versions in JSON format
      })
    })
  })
  // create a version and send back all versions after creation
  router.post('/add', function(req, res, next) {
    var vals = req.body
    if(!('comment' in vals) || !('version' in vals)) {
      return helper.createErr("Comment and Version are required parameters.", res)
    }
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM versions WHERE version='"+vals.version+"'", function(err, ver) {
        if(ver.length) helper.createErr("The version "+vals.version+" already exists.")
      })
      conn.query("INSERT INTO versions(version,comment) VALUES('"+vals.version+"','"+vals.comment+"')", function(err, ver) {
        if (err) return helper.handleErr(err, res)
        logger.info("New version added. Version: '"+vals.version+"' Comment: '"+vals.comment+"'")
        res.json({"status":"ok", "message":"Version added."})
      })
    })
  })
  // Retrieve a single version
  router.get('/:ver_id', function(req, res, next) {
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT *, DATE_FORMAT(st.launch_date, '%Y-%m-%d %H:%i:%s') AS launch FROM versions v LEFT JOIN state_transition st ON (st.version_id=v.id) WHERE v.id="+req.params.ver_id, function(err, ver) {
        // if there is an error retrieving, send the error.
        if (err) return helper.handleErr(err, res)
        if (ver.length){
          res.json(ver)
        } else {
          return helper.createErr("No results found.", res)
        }
      })
    })
  })
  // Update a version by ID
  router.post('/edit/:ver_id', function(req, res, next) {
    var vals = req.body
    if (!req.params.ver_id) {
      return helper.createErr("Must provide a version id.", res)
    }
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM versions WHERE id="+req.params.ver_id, function(err, ver) {
        if (err) return helper.handleErr(err, res)
        //Update the comment for the version since this is the only thing about a version we can update.
        if (ver.length) {
          conn.query("UPDATE versions SET comment='"+vals.comment+"' WHERE id="+req.params.ver_id, function(err) {
            if (err) return helper.handleErr(err, res)
            conn.query("SELECT * FROM versions WHERE id="+req.params.ver_id, function(err, newver) {
              logger.info('Version updated from '+JSON.stringify(ver[0])+' to '+JSON.stringify(newver[0]))
              res.json({"status":"ok", "message":"Version updated."})
            })
          })
        } else {
          return helper.createErr("No results found.", res)
        }
      })
    })
  })
  //Get all versions that match the provided search criteria
  router.post('/search', function(req, res, next) {
    //version: *.*.*.***** - Search for any version that matches up to the maximum number of characters (a full version string)
    //state: Search for versions and the appropriate state transitions that match the state
    //date_start: Search for versions that have state transition(s) from the given start date (to now if no end date provided)
    //date_end: Search for version that have state transition(s) to a given end date (from a start date if provided, otherwise from the beginning of time)
    var vals = req.body
    if (Object.keys(vals).length == 0) {
      //Create an error cause we can't search for nothing.
      return helper.createErr("Must provide at least one search parameter (version, state, date start, or date end).", res)
    } else {
      pool.getConnection(function(err, conn) {
        if (err) return helper.handleErr(err, res)
        //Initialize the query and then append to it as required
        q = "SELECT *, DATE_FORMAT(st.launch_date, '%Y-%m-%d %H:%i:%s') AS launch FROM versions v LEFT JOIN state_transition st on (v.id = st.version_id) WHERE"
        if ('version' in vals) {
          q = helper.addWhere(q, " v.version LIKE '"+vals.version+"%'")
        }
        if ('state' in vals) {
          q = helper.addWhere(q, " st.state="+vals.state)
        }
        if ('date_start' in vals && !('date_end' in vals)) {
          q = helper.addWhere(q, " DATE(st.launch_date) > '"+vals.date_start+"'")
        } else if (!('date_start' in vals) && 'date_end' in vals) {
          q = helper.addWhere(q, " DATE(st.launch_date) < '"+vals.date_end+"'")
        } else if ('date_start' in vals && 'date_end' in vals) {
          q = helper.addWhere(q," DATE(st.launch_date) BETWEEN '"+vals.date_start+"' AND '"+vals.date_end+"'")
        }
        conn.query(q, function(err, vers) {
          if (err) return helper.handleErr(err, res)
          if (vers.length) {
            res.json(vers)
          } else {
            res.json({"results": "No results found."})
          }
        })
      })//end of connection object retrieved from pool
    }
  }) //end of get "search" request)
  return router
}//end module

/************************************************************************************
STATES.JS
Description: Module holding all routes for the state section of the Version REST API.
            All functions in this module handle the states. Add a new state, get all
            states for a given version, get a list of the states available.
************************************************************************************/
module.exports = function(app, pool, logger, express, jwt) {
  var helper = require("../modules/helpers")(logger)
  var router = express.Router()
  // Get all states (ids and names)
  router.get('/list', function(req, res) {
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM states", function(err, sts) {
        if (err) return helper.handleErr(err, res)
        res.json(sts)
      })
    })
  })
  //Add a new state for a version. When done, pass back the updated version with it's states.
  router.post('/add/:ver_id', function(req, res) {
    var vals = req.body
    if (!('state' in vals) || !('launch' in vals)) helper.createErr("A state and launch date are required.", res)
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM versions WHERE id="+req.params.ver_id, function(err, ver) {
        if (err) return helper.handleErr(err, res)
        if (!ver.length) {
          //No result was found.
          return helper.createErr("A version with id +"+req.params.ver_id+" does not exist.", res)
        }
        conn.query("SELECT * FROM state_transition WHERE version_id="+ver[0].id+" AND state="+vals.state+" AND launch_date='"+vals.launch+"'", function(err, st) {
          if (err) return helper.handleErr(err, res)
          if (st.length) return helper.createErr("The version "+ver[0].version+" already has an entry for state "+vals.state, res)
        })
        console.log("INSERT INTO state_transition(version_id,state,launch_date) VALUES("+ver[0].id+", "+vals.state+", '"+vals.launch+"')")
        conn.query("INSERT INTO state_transition(version_id,state,launch_date) VALUES("+ver[0].id+", "+vals.state+", '"+vals.launch+"')", function(err, out) {
          if (err) return helper.handleErr(err, res)
          logger.info("New state added for version "+ver[0].version)
          res.json({"status":"ok", "message":"State added."})
        })
      })
    })
  })
  //Update the launch date of a state for a version
  router.post('/update/:ver_id/:state', function(req, res) {
    var vals = req.body
    if (!('launch_date' in vals)) helper.createErr("A launch date is required.", res)
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM versions WHERE id="+req.params.ver_id, function(err, ver) {
        if (err) return helper.handleErr(err, res)
        if (!ver.length) {
          //No result was found.
          return helper.createErr("A version with id +"+req.params.ver_id+" does not exist.", res)
        }
        conn.query("SELECT * FROM state_transition WHERE version_id="+ver[0].id+" AND state="+req.params.state, function(err, st) {
          if (err) return helper.handleErr(err, res)
          if (!st.length) return helper.createErr("This state does not exist yet for this version.", res)
          conn.query("UPDATE state_transition SET launch_date='"+vals.launch_date+"' WHERE version_id="+ver[0].id+" AND state="+req.params.state, function(err, out) {
            if (err) return helper.handleErr(err, res)
            logger.info("Launch date updated.")
            res.json({"status":"ok", "message":"Launch date updated."})
          })
        })
      })
    })
  })
  // Get a state and it's name by the id.
  router.get('/:state', function(req, res) {
    pool.getConnection(function(err, conn) {
      if (err) return helper.handleErr(err, res)
      conn.query("SELECT * FROM states WHERE state_id="+req.params.state, function(err, sts) {
        if (err) return helper.handleErr(err, res)
        res.json(sts[0])
      })
    })
  })
  return router
}

既然我的猜测是问题所在,我会把它放在一个答案中,这样你就可以结束这个问题了。

你的症状听起来可能是你没有关闭连接(将其返回到连接池),所以在几次请求后,连接池是空的,服务器只是坐在那里等待连接可用。

最新更新