epi
Version:
A Api Service Framework Base On Express.js
724 lines (545 loc) • 18.6 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: HttpServer.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: HttpServer.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @desc 封装express创建服务的方法
* @author sam
* @version 0.8.3
* */
var https = require('https');
var cluster = require('cluster');
var os = require('os');
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var express = require('express');
/**
* @desc 创建一个http服务程序,包括https和http服务
* @constructor HttpServer
* @this {HttpServer}
* @param {Object} options
* @example
*
*
*'use strict';
*
*var HttpServer = require('epi').HttpServer;
*
*var util = require('util');
*
* var config = {
* host : null,
* key : 'string', //https监听时需要这个key
* cert : 'string', //https监听的时候需要证书
* version : '1.0.0' //api默认的版本信息
* port : {
* http : 8000, //如果想要监听http端口,直接写
* https : 4433 //如果不想监听https,直接置为null
* }
* }
*
* //创建一个httpServer=====================================
* var httpServer = new HttpServer(config);
*
*
* //设置==================================================
* httpServer.setting(function (app) {
* app.set('trust proxy', true);
* app.set('x-powered-by', false);
* });
* //导入中间件=============================================
* var body = require('body-parser');
* var cookie = require('cookie-parser');
* var compression = require("compression");
*
* //应用中间件
* httpServer.use(function (app) {
* app.use(compression());
* app.use(cookie());
* app.use(body.json());
* app.use(body.urlencoded({
* extended: true
* }));
* });
*
*
* //导入路由==============================================
* var testRouter = require('./router/test');
*
* //注册路由
* testRouter.map(httpServer);
* //错误处理=============================================
* httpServer.error(function (err, req, res, next) {
* console.error(err.stack);
* res.status(500).json({
* error: err
* });
* });
* */
var HttpServer = function (options) {
/* *
* {
* host : null,
* key : 'string',
* cert : 'string',
* version : '1.0.0' //api默认的版本信息
* port : {
* http : 8000,
* https : 4433
* }
* }
* */
options = options || {};
EventEmitter.call(this);
this.__host = options.host || null;
this.__version = options.version;
this.__key = options.key;
this.__cert = options.cert;
this.__port = {
http: options.port.http,
https: options.port.https
};
this.__server = null;
/**
* 如果调用cluster方法启动程序,所有子进程都在这里
* */
this.workers = null;
/**
* express 创建的app,如果想调用express的相关方法,可以使用这个app
* */
this.app = null;
this.__init();
};
util.inherits(HttpServer, EventEmitter);
/**
* @desc 初始化系统
* @access private
* */
HttpServer.prototype.__init = function () {
this.app = express();
if (this.__port.https) {
if (!this.__key || !this.__cert) {
throw new Error('listen https need key and cert');
}
this.__server = https.createServer({
key: this.__key,
cert: this.__cert
}, this.app);
}
/**
* 用于解析version和device的中间件
* 添加一个解析version和device设备类型的中间件
*/
this.app.use(function (req, res, next) {
req.startTime = Date.now();
req.version = req.get('accept-version') || req.query.version;
req.channel = req.get('client-channel') || req.query.channel;
req.cache = {
use : req.get('use-api-cache') ? true : false,
ttl : null,
check : function(callback){
callback();
}
};
next();
});
return this.app;
};
/***
* @desc handler
* */
var routerHandler = function (options, handler, ttl) {
return function(req, res, next){
if (options.v && req.version !== options.v) {
return next();
}
if (options.c && req.channel !== options.c) {
return next();
}
if(util.isNumber(cache) && req.cache && (req.cache.use == true) && util.isFunction(req.cache.check)){
req.cache.check(function(err, result){
if(!err && result){
res.set('data-from-cache', 'true');
return res.send(result);
}else{
req.cache.ttl = ttl;
handler(req, res, next);
}
});
}else{
handler(req, res, next);
}
}
};
/**
* @desc Router.all 相当于express router.all
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.all('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.all('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.all('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.all = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.all(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.get 相当于express router.get
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.get('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.get('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.get('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.get = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
var self = this;
options = options || {};
options.v = options.v || self.__version;
self.app.get(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.post 相当于express router.post
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.post('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.post('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.post('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.post = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.post(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.put 相当于express router.put
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.put('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.put('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.put('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.put = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.put(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.delete 相当于express router.delete
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.delete('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.delete('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.delete('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.delete = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.delete(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.header 相当于express router.header
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.header('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.header('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.header('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.header = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.header(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.options 相当于express router.options
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.options('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.options('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.options('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.options = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.options(path, routerHandler(options, handler, ttl));
};
/**
* @desc Router.trace 相当于express router.trace
* @param {String | Regex} path '/api/name' | /^\/api\/name$/
* @param {String} options .v '1.0.1'
* @param {String} options .c 你定义的频道类型
* @param handler {Function} function(req, res, next){}
* @param ttl {Number} 设置api缓存时间
* @example
* 使用缓存:
* httpServer.trace('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, 100)
*
* 不使用
* httpServer.trace('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){})
* httpServer.trace('/test', {v : '1.0.0', c : 'pc'}, function(req, res, next){}, null)
* */
HttpServer.prototype.trace = function (path, options, handler, ttl) {
if (!util.isObject(options)) {
throw new Error('options is object {v : "1.0.0", c : "pc"}');
}
options = options || {};
options.v = options.v || this.__version;
this.app.trace(path, routerHandler(options, handler, ttl));
};
/**
* @desc 设置程序属性
* @param {Function} fn function(app){}
* @example
* httpServer.setting(function (app) {
* app.set('trust proxy', true);
* app.set('x-powered-by', false);
* });
* */
HttpServer.prototype.setting = function (fn) {
fn(this.app);
};
/**
* @desc 应用中间件
* @param fn {Function} function(app){}
* @example
* httpServer.use(function(app){
* app.use(compression());
* app.use(timeout('10s'));
* app.use(cookie());
* app.use(body.json());
* });
* */
HttpServer.prototype.use = function (fn) {
fn(this.app);
};
/**
* @desc 注册路由
* @param fn {Function} function(app){}
* */
HttpServer.prototype.route = function (fn) {
fn(this.app);
};
/**
* @desc 添加错误处理
* @param fn {Function} function(err, req, res, next){}
* */
HttpServer.prototype.error = function (fn) {
this.app.use(function (err, req, res, next) {
fn(err, res, res, next);
});
};
/**
* @desc 监听端口
* @param callback {Function} 监听后返回的消息
* @example
* httpServer.listen(8000, function(err, message){
* console.log(message);
* })
* */
HttpServer.prototype.listen = function (callback) {
if (!this.__port.http && !this.__port.https) {
throw new Error('port.http or port.https is not set');
}
var listenMessage = '';
var flag = 0;
var count = 0;
var self = this;
if (this.__port.http) {
count++;
}
if (this.__port.https) {
count++;
}
if (this.__port.http) {
this.app.listen(this.__port.http, self.__host, function (err) {
flag++;
if (err) {
listenMessage += err.message;
}
var host = self.__host || '127.0.0.1';
listenMessage += 'server listen on : http://' +
host +
':' +
self.__port.http +
', pid : ' +
process.pid;
if (flag >= count) {
self.emit('listen', self.__port.http);
callback && callback(listenMessage);
}
});
}
if (this.__port.https) {
this.__server.listen(this.__port.https, self.__host, function (err) {
flag++;
if (err) {
listenMessage += err.message;
}
var host = self.__host || '127.0.0.1';
listenMessage += '\nserver listen on : https://' +
host +
':' +
self.__port.https +
', pid : ' +
process.pid;
if (flag >= count) {
self.emit('listen', self.__port.https);
callback && callback(listenMessage);
}
});
}
};
/**
* @desc 以集群的方式启动程序
* @param number {Number} 要启动的监听进程数量,null || 0 启动和 cpu个数 - 1 的进程数量
* @param callback {Function} 监听后返回的消息
* @example
* //子进程启动事件
* httpServer.on('childStart', function(worker){
* //记录子进程启动
* logger.info(Date.now(), worker.pid);
* });
*
*
* //子进程退出事件
* httpServer.on('childStop', function(worker, code, signal){
* //记录子进程非正常退出
* if(!signal && code !== 0){
* logger.fatal(Date.now(), worker.pid, code, signal);
* }
* });
*
* //子进程退出事件
* httpServer.on('childRestart', function(worker){
* //记录子进程重启
* logger.fatal(Date.now(), worker.pid);
* });
*
*
* //使用集群方式监听=======================================
* httpServer.cluster(0, function (message) {
* console.log(message);
* });
* */
HttpServer.prototype.cluster = function (number, callback) {
var self = this;
var cpuCount = number || os.cpus().length - 1;
self.workers = {};
if (cluster.isMaster) {
for (var i = 0; i < cpuCount; i++) {
var workerProcess = cluster.fork();
self.workers[workerProcess.process.pid] = workerProcess;
self.emit('childStart', workerProcess);
}
cluster.on('exit', function (worker, code, signal) {
self.emit('childStop', worker, code, signal);
delete self.workers[worker.process.pid];
setTimeout(function(){
var workProcess = cluster.fork();
self.workers[workProcess.process.pid] = cluster.fork();
self.emit('childRestart', workProcess);
}, 1000);
});
} else {
self.listen(callback);
}
};
exports.HttpServer = HttpServer;</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="HttpServer.html">HttpServer</a></li></ul><h3>Global</h3><ul><li><a href="global.html#app">app</a></li><li><a href="global.html#https">https</a></li><li><a href="global.html#workers">workers</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.2</a> on Sun Sep 20 2015 11:45:44 GMT+0800 (CST)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>