UNPKG

7.53 kBJavaScriptView Raw
1/*!
2 * apracjs
3 * Copyright(c) 2017 by wssf
4 * 2017-04-26
5 * 对外公开的包、及方法接口信息等
6 * 内部主要是使用包装后的connect创建server
7 * 初始化config配置信息
8 * 定义路由请求顺序
9 */
10
11'use strict';
12var config = require('./config.js').apracConfig;
13var http = require('http');
14var path = require('path');
15var debug = require('debug')('aprac:app');
16var Router = require('./handlers/router.js');
17var staticHandler = require('./handlers/static.js');
18var gspxHandler = require('./handlers/gspx/gspx.js');
19var ajaxHandler = require('./handlers/ajax/ajax.js');
20var axdHandler = require('./handlers/axd.js');
21var connect = require('./handlers/connect.js')();
22var utils = require('./common/utils.js');
23var finalhandler = require('finalhandler');
24var compression = require('compression');
25var cookieParser = require('cookie-parser');
26var session = require('express-session');
27var bodyParser = require('body-parser');
28var CoreDistributor = require('./distributor/coreDistributor.js');
29var url = require("url");
30var RedisStore = require('connect-redis')(session);
31
32class Aprac {
33 constructor() {
34 this.settings = config;
35 this.defaultConfiguration();
36 }
37
38 defaultConfiguration() {
39 debug('booting in %s mode', this.get('env'));
40
41 this.set('staticTag', '*');
42 this.set('ajaxTag', '.ajax'); // 数据服务引擎
43 this.set('webPath', path.join(process.cwd(), this.get('webFolder')));
44
45 this._initRouter();
46
47 }
48
49 _initRouter() {
50 if (this._router) return;
51 this._router = new Router(this);
52 this.registerRouter();
53
54 connect.use(utils.createDelegate(this, this.checkMethod));
55 connect.use(compression()); // 不管是页面还是资源,都需要压缩,因此放最前面
56 connect.use(utils.createDelegate(this, this.startHandler)); // 必须放其它层的前面,接收请求前先判断类型
57
58 connect.use(cookieParser(config.cookieSecret));
59
60 let sessionConfig = {
61 secret: config.cookieSecret, // 与cookieParser中的一致
62 name: config.sessionIdKey,
63 cookie: {
64 maxAge: config.sessionTimeout * 60 * 1000 // 20分钟过期
65 },
66 resave: config.SessionResave,
67 saveUninitialized: config.SessionSaveUninitialized
68 };
69
70 if (config.sessionConn) {
71 let sessionConnUrlInfo = url.parse(config.sessionConn);
72 //选择缓存数据库
73 if (sessionConnUrlInfo.protocol === "redis:") {
74 let dbName = parseInt(sessionConnUrlInfo.pathname.substr(1, sessionConnUrlInfo.pathname.length - 1));
75 let port = parseInt(sessionConnUrlInfo.port);
76 sessionConfig.store = new RedisStore({
77 host: sessionConnUrlInfo.hostname,
78 port: port,
79 db: dbName,
80 pass: sessionConnUrlInfo.auth
81 });
82 }
83 }
84 connect.use(session(sessionConfig));
85
86 connect.use(bodyParser.json(this._getJsonDefaultOptions({ reviver: this.dateReviver })));
87 connect.use(bodyParser.raw(this._getJsonDefaultOptions({})));
88 connect.use(bodyParser.text(this._getJsonDefaultOptions({})));//接收外部传过来的文本数据,如c#中通过webclient的upload数据,需要指定webclient的content-type:text/plain
89 connect.use(bodyParser.urlencoded(this._getJsonDefaultOptions({ extended: false }))); // 用于打印管理器没安装时,点击导出Excel
90
91 connect.use(utils.createDelegate(this, this.endHandle)); // 平台中间件
92
93 connect.use(this.errorHandler); // 中间件发生异常拦截器
94 debug('router add finish');
95 }
96
97 registerRouter() {
98 this.registerDistributor();
99
100 //注册分发器的handler
101 var apracConfigDistributor = config.Distributor;
102 if (apracConfigDistributor) {
103 for (var i in apracConfigDistributor) {
104 var item = apracConfigDistributor[i];
105 this.registerDistributor(item);
106 }
107 }
108 }
109
110 registerDistributor(appConfig) {//根据appName区分处理器
111 var core = undefined;
112 if (appConfig) {
113 core = new CoreDistributor(appConfig);
114 }
115 // this._router.addHandler(new staticHandler(this, this.get('staticTag'))); // 解析静态文件请求
116 this._router.addHandler(new staticHandler(this, core)); // 解析静态文件请求
117 this._router.addHandler(new gspxHandler(this, core)); // 解析gspx请求
118 this._router.addHandler(new ajaxHandler(this, core)); // 解析ajax请求
119 this._router.addHandler(new axdHandler(this, core)); // 解析带版本号的资源请求
120 }
121
122 _getJsonDefaultOptions(options) {
123 options.limit = config.jsonLimit;
124 return options;
125 }
126
127 dateReviver(key, value) { // carpa3前端js序列化日志格式为时间戳ticks,需要服务端单独做转换为Date
128 if (typeof value === 'string') {
129 var a = /^\/Date\((-?[\d.]+?)\)\/$/.exec(value);
130 if (a) {
131 return new Date(Number(a[1]));
132 }
133 }
134 return value;
135 }
136
137 checkMethod(req, res, next) {
138 res.req = req;
139 var isOPTIONS = req.method == "OPTIONS";
140 var allowHeaders = config.defaultAllowHeaders; // 平台默认请求头
141 if (config.allowHeaders) allowHeaders += ',' + config.allowHeaders; // 产品自定义请求头
142
143 utils.setCORSHeader(res, config.allowOrigins, allowHeaders, config.withCredentials, isOPTIONS); // 预先检查并统一输出跨域请求头
144
145 if (isOPTIONS) { // 跨域请求预检查
146 res.end('ok'); // 预检查不继续处理业务逻辑,直接返回
147 return;
148 }
149 next(); // 继续处理
150 }
151
152 startHandler(req, res, next) {
153 var handler = this._router.handle(req, res);
154 handler.init(req, res);
155
156 if (handler.enableSession(req)) { // handler自行判断,减少验证
157 req._apracHandler = handler; // 注入,存起来
158 next();
159 return;
160 }
161
162 handler.processRequest(req, res, this.getDone(req, res)); // 请求类型分发处理,如果是资源类请求,直接跳过session、cookie、Parser等(按情况)
163 }
164
165 endHandle(req, res, done) {
166 req._apracHandler.processRequest(req, res, this.getDone(req, res));
167 }
168
169 getDone(req, res) {
170 var done = finalhandler(req, res, {
171 env: this.get('env'),
172 onerror: this.logerror.bind(this)
173 });
174 return done;
175 }
176
177 errorHandler(ex, req, res, next) {
178 res.writeHead(res.statusCode, { 'Content-Type': "application/json; charset=utf-8" });
179 if (ex.type === 'entity.too.large') {
180 const msg = "请求数据过大,请联系管理员调整数据大小";
181 res.end(JSON.stringify({ Message: msg, msg }));
182 return;
183 }
184 if (ex.notFound) {
185 res.statusCode = 404;
186 } else {
187 res.statusCode = 500;
188 }
189 var errorObj = { "Message": utils.makeExceptionHtml(ex, false) };
190 res.end(JSON.stringify(errorObj));
191 }
192
193 set(name, val) {
194 if (arguments.length === 1) {
195 return this.get[name];
196 }
197 this.settings[name] = val;
198 return this;
199 }
200
201 get(setting) {
202 return this.settings[setting];
203 }
204
205 listen(port, hostname, callback) {
206 var server = connect.listen(port, hostname, callback);
207 return server;
208 }
209
210 logerror(err) {
211 if (this.get('env') !== 'test') {
212 var msg = '';
213 if (err.message) {
214 msg = err.message;
215 } else {
216 msg = err.stack || err.toString();
217 }
218 console.error(msg);
219 }
220 }
221}
222
223exports = module.exports = Aprac;
\No newline at end of file