1714 words
|
28.57 分钟
express实践
2017-04-30

Node.js 7.0发布之前,写一篇关于express的文章

项目创建

使用express-generator

  • 使用npm install express-generator -g

代码修改自动重启

使用nodemon

  • nodemon ./bin/www

全局设置

//加载配置项
global.Config = require(path.resolve(Root, './config/config'))
//通用方法(设置为全局对象,方便调用)
global.F = require(path.resolve(Root, './common/funcs'))
//socket事件方法
global.Socket = require(path.resolve(Root, './socket/socket'))
//加载所有的数据库model
global.M = {}
//model存储路径 (暂时不支持二级目录)
var modelsPath = path.resolve(Root, 'models')
fs.readdirSync(modelsPath).forEach(function (name) {
  if (path.extname(name) !== '') {
    name = path.basename(name, '.js')
    M[name] = require(path.resolve(modelsPath, name))
  }
})

使用co、Promise(bluebird)进行异步处理

定义通用方法run实行Promise,并抛出错误

let run = (fn, next) => {
  co(fn).catch((err) => {
    next(err)
  })
}

通用方法列表 (大部分抄袭thinkjs)

module.exports = {
  run: run,
  promisify: promisify,
  camelCase: camelCase,
  defer: defer,
  Class: Class,
  extend: extend,
  isClass: isClass,
  isBoolean: isBoolean,
  isNumber: isNumber,
  isObject: isObject,
  isString: isString,
  isArray: isArray,
  isFunction: isFunction,
  isDate: util.isDate,
  isRegExp: util.isRegExp,
  isError: util.isError,
  isIP: net.isIP,
  isIP4: net.isIPv4,
  isIP6: net.isIPv6,
  isFile: isFile,
  isFileAsync: isFileAsync,
  isDir: isDir,
  isDirAsync: isDirAsync,
  isNumberString: isNumberString,
  isPromise: isPromise,
  isWritable: isWritable,
  isBuffer: isBuffer,
  isTrueEmpty: isTrueEmpty,
  isEmpty: isEmpty,
  clone: clone,
  mkdir: mkdir,
  rmdir: rmdir,
  md5: md5,
  chmod: chmod,
  getFiles: getFiles,
  escapeHtml: escapeHtml,
  datetime: datetime,
  getDateTime: getDateTime,
  randomString: randomString,
}

数据库操作(mysql)

简单的数据库查询,没有封装sql(懒)

var mysql = require('mysql')
var Promise = require('bluebird')
var dbConfig = Config.db

var pool = mysql.createPool(dbConfig)

//使用连接池
let query = (sql) => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, connection) => {
      connection.query(sql, function (err, result) {
        return err ? reject(err) : resolve(result)
      })
      connection.release()
    })
  })
}

let insert = (table, data) => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, connection) => {
      connection.query(
        'INSERT INTO {table} SET ?',
        data,
        function (err, result) {
          return err ? reject(err) : resolve(result.insertId)
        }
      )
      connection.release()
    })
  })
}

//普通连接
let queryTest = (sql) => {
  var connection = mysql.createConnection(dbConfig)
  return new Promise((resolve, reject) => {
    connection.connect()
    connection.query(sql, (err, rows, fields) => {
      return err ? reject(err) : resolve(rows)
    })
    connection.end()
  })
}

module.exports = {
  query: query,
  queryTest: queryTest,
}

数据库连接测试代码 (使用了上面定义的run方法)

router.get('/', function (req, res, next) {
  // 数据库操作测试
  F.run(function* () {
    var result = yield Db.query('SELECT * FROM fruitscities limit 5')
    var result = yield Db.query('SELECT * FROM fruitscities limit 5')
    req.session.admin = '111111111'
    console.log(req.session.admin)
    res.render('index', { title: 'Express```' })
  }, next)
})

router.get('/test', function (req, res, next) {
  console.log(req.baseUrl)
  console.log(req.route)
  console.log(req.path)
  // 数据库操作测试
  F.run(function* () {
    var result = yield Db.query('SELECT * FROM fruitscities limit 5')
    var result = yield Db.query('SELECT * FROM fruitscities limit 5')
    console.log(req.session.admin)
  }, next)
})

使用nunjucks模板引擎

//模板引擎
var nunjucks = require('nunjucks')
// 模板引擎设置
var env = new nunjucks.configure(path.join(__dirname, 'views'), {
  // 设置模板文件的目录,为views
  autoescape: true,
  watch: true,
  express: app,
})
app.set('view engine', 'html')

使用nunjucks模板标签(用于cms,文章,新闻展示等)

//标签测试
var tags = require(path.resolve(Root, './common/tags'))

//绑定标签
env.addExtension('tagtest', new tags.tagtest())
common / tags.js中的代码

var tags
var nunjucks = require('nunjucks')
tags = {
  tagtest: function () {
    //tag标签测试
    this.tags = ['tagtest']
    this.parse = function (parser, nodes, lexer) {
      let tok = parser.nextToken()
      var args = parser.parseSignature(null, true)
      parser.advanceAfterBlockEnd(tok.value)
      let body = parser.parseUntilBlocks('endtagtest') // 结束标签
      parser.advanceAfterBlockEnd()
      //return new nodes.CallExtension(this, 'run', args);
      return new nodes.CallExtensionAsync(this, 'run', args, [body]) //异步调用
    }
    this.run = function (context, args, body, callback) {
      console.log(JSON.stringify(args)) //前台返回参数
      var data = [
        {
          id: 1,
          city: '北京',
          parent: 0,
          spelling: 'BeiJing',
          abbr: 'BJ',
          short: 'B',
        },
        {
          id: 2,
          city: '上海',
          parent: 0,
          spelling: 'ShangHai',
          abbr: 'SH',
          short: 'S',
        },
        {
          id: 3,
          city: '天津',
          parent: 0,
          spelling: 'TianJin',
          abbr: 'TJ',
          short: 'T',
        },
        {
          id: 4,
          city: '重庆',
          parent: 0,
          spelling: 'ZhongQing',
          abbr: 'ZQ',
          short: 'Z',
        },
        {
          id: 5,
          city: '黑龙江',
          parent: 0,
          spelling: 'HeiLongJiang',
          abbr: 'HLJ',
          short: 'H',
        },
      ]
      context.ctx['list'] = data //返回参数
      let result = new nunjucks.runtime.SafeString(body())
      return callback(null, result)
    }
  },
}

module.exports = tags

页面中使用

{% tagtest list="key1=1,key2=2,key3=3,key4=4" %}

  {% for val in list %}


    {{ val.id }}:{{ val.city}}


  {% endfor %}

{% endtagtest %}


{% tagtest key1=1,key2=2,key3=3,key4=4 %}

  {% for val in list %}


    {{ val.id }}:{{ val.city}}


  {% endfor %}

{% endtagtest %}

使用log4js进行日志记录

记录access日志

app.use(log4js.connectLogger(log4js.getLogger('log_access'), { level: 'INFO' }))

配置文件 (配置可以根据需求修改)

module.exports = {
  db: {
    host: '',
    user: '',
    password: '',
    database: '',
  },
  cookieSession: {
    name: 'session_uuice',
    keys: ['key1', 'key2'],
    secret: 'ksjf493248kjkj',
  },
  log4js: {
    appenders: [
      {
        type: 'console',
        category: 'console',
      },
      {
        category: 'log_file',
        type: 'file',
        filename: './logs/log_file/file.log',
        maxLogSize: 104800,
        backups: 100,
      },
      {
        category: 'log_date',
        type: 'dateFile',
        filename: './logs/log_date/date',
        alwaysIncludePattern: true,
        pattern: '-yyyy-MM-dd-hh.log',
      },
      {
        category: 'log_access',
        type: 'dateFile',
        filename: './logs/log_access/date',
        alwaysIncludePattern: true,
        pattern: '-yyyy-MM-dd-hh.log',
      },
    ],
    replaceConsole: true,
    levels: {
      log_file: 'ALL',
      console: 'ALL',
      log_date: 'ALL',
    },
  },
}

其他记录日志代码

console.log('log_start start!')

var LogFile = log4js.getLogger('log_file')

LogFile.trace('This is a Log4js-Test')
LogFile.debug('We Write Logs with log4js')
LogFile.info('You can find logs-files in the log-dir')
LogFile.warn('log-dir is a configuration-item in the log4js.json')
LogFile.error("In This Test log-dir is : './logs/log_test/'")

console.log('log_start end!')

var log_date = log4js.getLogger('log_date')

log_date.trace('This is a Log4js-Test')
log_date.debug('We Write Logs with log4js')
log_date.info('You can find logs-files in the log-dir')
log_date.warn('log-dir is a configuration-item in the log4js.json')
log_date.error("In This Test log-dir is : './logs/log_test/'")

console.log('log_date end!')

socket通讯

使用socket.io 在项目bin/www中添加

//添加socket.io支持
var io = require('socket.io')(server)
io.on('connection', function (socket) {
  Socket(socket, io) //这里的Socket,就是app.js定义的全局变量
})

在app.js中添加事件逻辑

//socket事件方法
global.Socket = require(path.resolve(Root, './socket/socket'))

错误处理 Promise中的报错

let run = (fn, next) => {
  co(fn).catch((err) => {
    next(err)
  })
}

其他报错

// 将404交给错误处理中间件
app.use(function (req, res, next) {
  var err = new Error('Not Found')
  err.status = 404
  next(err)
})

// 错误处理

//开发环境报错,显示错误堆栈
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    res.status(err.status || 500)
    if (req.xhr) {
      res.json({
        status: err.status,
        message: err.message,
        error: err.stack,
      })
    } else {
      res.render('error', {
        status: err.status,
        message: err.message,
        error: err,
      })
    }
  })
}

//生产环境报错,不展示错误堆栈
app.use(function (err, req, res, next) {
  res.status(err.status || 500)
  if (req.xhr) {
    res.json({
      status: err.status,
      message: err.message,
      error: {},
    })
  } else {
    res.render('error', {
      status: err.status,
      message: err.message,
      error: {},
    })
  }
})

其他

待补充

http://localhost:3000/archives/express-shi-jian
Author
Unknown
Published at
2017-04-30