优化中间件/路由/跨域
parent
b2c424a384
commit
38ad516e08
61
index.js
61
index.js
|
@ -36,9 +36,8 @@ function hideProperty(host, name, value) {
|
||||||
export default class Five {
|
export default class Five {
|
||||||
constructor() {
|
constructor() {
|
||||||
hideProperty(this, '__FIVE__', Object.assign({}, init))
|
hideProperty(this, '__FIVE__', Object.assign({}, init))
|
||||||
hideProperty(this, '__MODULES__', { __error__: null })
|
hideProperty(this, '__MODULES__', {})
|
||||||
hideProperty(this, '__MIDDLEWARE__', [])
|
hideProperty(this, '__MIDDLEWARE__', [])
|
||||||
hideProperty(this, '__INSTANCE__', {})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__init__() {
|
__init__() {
|
||||||
|
@ -94,63 +93,51 @@ export default class Five {
|
||||||
|
|
||||||
// 获取全局配置
|
// 获取全局配置
|
||||||
get(key) {
|
get(key) {
|
||||||
try {
|
return this.__FIVE__[key]
|
||||||
return new Function('o', `return o.${key}`)(this.__FIVE__)
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载中间件/缓存模块
|
// 加载中间件
|
||||||
// 与别的中间件用法有些不一样, 回调的传入参数中的req和res,
|
// 与别的中间件用法有些不一样, 回调的传入参数中的req和res,
|
||||||
// 并非原生的request对象和response对象,
|
// 并非原生的request对象和response对象,
|
||||||
// 而是框架内部封装过的,可通过origin属性访问原生的对象
|
// 而是框架内部封装过的,可通过origin属性访问原生的对象
|
||||||
use(key, fn) {
|
use(fn) {
|
||||||
if (arguments.length === 1) {
|
if (typeof fn === 'function') {
|
||||||
if (typeof key !== 'function') {
|
this.__MIDDLEWARE__.push(fn)
|
||||||
throw TypeError('argument 1 must be a callback')
|
return this
|
||||||
}
|
|
||||||
this.__MIDDLEWARE__.push(key)
|
|
||||||
} else {
|
|
||||||
if (typeof key !== 'string') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
libs[key] = fn
|
|
||||||
}
|
}
|
||||||
|
throw TypeError('argument must be a callback')
|
||||||
}
|
}
|
||||||
// 预加载应用
|
|
||||||
|
// 预加载应用, 缓存以提高性能
|
||||||
preload(dir) {
|
preload(dir) {
|
||||||
var list = fs.ls(dir)
|
var list = fs.ls(dir)
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
list.forEach(file => {
|
list.forEach(item => {
|
||||||
var { name } = path.parse(file)
|
var { name } = path.parse(item)
|
||||||
if (name.startsWith('.')) {
|
if (name.startsWith('.')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
// 如果是目录,则默认加载index.js, 其他文件不加载
|
||||||
this.__MODULES__[name] = import(file)
|
// 交由index.js自行处理, 用于复杂的应用
|
||||||
} catch (err) {
|
if (fs.isdir(item)) {
|
||||||
this.__MODULES__.__error__ = err
|
item = path.join(item, './index.js')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.__MODULES__[name] = import(item).catch(err => {
|
||||||
|
return { default: null }
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册实例化对象到实例池中
|
// 注入实例化对象到实例池中
|
||||||
// 与use方法不同的是, 这个会在server创建之前就已经执行
|
// 与use方法不同的是, 这个会在server创建之前就已经执行
|
||||||
ins(name, fn) {
|
install({ name, install }) {
|
||||||
var _this = this
|
this['$$' + name] = install.call(this, this.__FIVE__)
|
||||||
if (arguments.length === 1) {
|
return this
|
||||||
return this.__INSTANCE__[name]
|
|
||||||
}
|
|
||||||
if (typeof fn === 'function') {
|
|
||||||
fn.call(this, this.__FIVE__, function next(instance) {
|
|
||||||
if (instance) {
|
|
||||||
_this.__INSTANCE__[name] = instance
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动http服务
|
// 启动http服务
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
*
|
* 部分配置
|
||||||
* @authors yutent (yutent@doui.cc)
|
* @author yutent<yutent.io@gmail.com>
|
||||||
* @date 2016-05-15 14:37:47
|
* @date 2020/09/22 17:19:39
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict'
|
const ENV_PROD = 'production'
|
||||||
|
const ENV_DEV = 'development'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
db: {},
|
db: {},
|
||||||
|
@ -24,27 +24,30 @@ export default {
|
||||||
domain: '', // cookie域, 默认等于website
|
domain: '', // cookie域, 默认等于website
|
||||||
port: 3000,
|
port: 3000,
|
||||||
routeMode: 'action', // action | __main__
|
routeMode: 'action', // action | __main__
|
||||||
env: process.env.NODE_ENV === 'production' ? 'production' : 'development',
|
env: process.env.NODE_ENV === ENV_PROD ? ENV_PROD : ENV_DEV,
|
||||||
debug: process.env.NODE_ENV !== 'production', // debug模式
|
debug: process.env.NODE_ENV === ENV_DEV, // debug模式
|
||||||
smtp: {
|
smtp: {
|
||||||
host: 'smtp.example.com',
|
host: 'smtp.example.com',
|
||||||
port: 25,
|
port: 25,
|
||||||
mail: 'service@example.com',
|
mail: 'no-reply@example.com',
|
||||||
name: '系统邮件',
|
name: 'no-reply',
|
||||||
passwd: ''
|
passwd: ''
|
||||||
},
|
},
|
||||||
supportCredentials: false,
|
cors: {
|
||||||
credentialsRule: null,
|
enabled: false,
|
||||||
credentialsMaxAge: 0,
|
credentials: false,
|
||||||
|
origin: [], // ['abc.com', 'a.foo.com']
|
||||||
|
maxAge: 0
|
||||||
|
},
|
||||||
jwt: null, // jwt secret
|
jwt: null, // jwt secret
|
||||||
regexp: {
|
regexp: {
|
||||||
// 常用正则
|
// 常用正则
|
||||||
email: /^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/,
|
email: /^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/,
|
||||||
uname: /^[A-Za-z\d_]{4,16}$/,
|
uname: /^[A-Za-z\d_]{4,16}$/,
|
||||||
passwd: /^[\S]{6,20}$/,
|
passwd: /^\S{6,20}$/,
|
||||||
phone: /^1[34578]\d{9}$/,
|
phone: /^1[3456789]\d{9}$/,
|
||||||
idCard: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/,
|
idCard: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/,
|
||||||
CN: /^[\u4e00-\u9fa5]+$/,
|
cn: /^[\u4e00-\u9fa5]+$/,
|
||||||
qq: /^\d{5,12}$/
|
qq: /^\d{5,12}$/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,28 +7,29 @@
|
||||||
import url from 'url'
|
import url from 'url'
|
||||||
|
|
||||||
export default function(req, res, next) {
|
export default function(req, res, next) {
|
||||||
var supportCredentials = this.get('supportCredentials')
|
var CORS = this.get('cors')
|
||||||
var credentialsRule = this.get('credentialsRule')
|
|
||||||
var credentialsMaxAge = this.get('credentialsMaxAge')
|
|
||||||
|
|
||||||
if (supportCredentials) {
|
if (CORS.enabled) {
|
||||||
var origin = req.header('origin') || req.header('referer') || ''
|
var origin = req.header('origin') || req.header('referer') || ''
|
||||||
var headers = req.header('access-control-request-headers')
|
var headers = req.header('access-control-request-headers')
|
||||||
origin = url.parse(origin)
|
var { hostname, host, protocol } = url.parse(origin)
|
||||||
|
|
||||||
if (credentialsRule && origin.hostname) {
|
if (CORS.origin.length && hostname) {
|
||||||
if (!credentialsRule.test(origin.hostname)) {
|
if (!CORS.origin.includes(hostname)) {
|
||||||
return res.end('')
|
return res.end('')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.set('Access-Control-Allow-Credentials', 'true')
|
res.set('Access-Control-Allow-Credentials', 'true')
|
||||||
res.set('Access-Control-Allow-Origin', `${origin.protocol}//${origin.host}`)
|
res.set('Access-Control-Allow-Origin', `${protocol}//${host}`)
|
||||||
|
|
||||||
if (headers) {
|
if (headers) {
|
||||||
res.set('Access-Control-Allow-Headers', headers)
|
res.set('Access-Control-Allow-Headers', headers)
|
||||||
}
|
}
|
||||||
if (credentialsMaxAge) {
|
|
||||||
res.set('Access-Control-Max-Age', credentialsMaxAge)
|
if (CORS.maxAge) {
|
||||||
|
res.set('Access-Control-Max-Age', CORS.maxAge)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
return res.end('')
|
return res.end('')
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,14 @@
|
||||||
|
|
||||||
export default function(req, res, next) {
|
export default function(req, res, next) {
|
||||||
var debug = this.get('debug')
|
var debug = this.get('debug')
|
||||||
|
if (this.__MODULES__.__error__) {
|
||||||
|
var err = this.__MODULES__.__error__
|
||||||
|
return res.error(debug ? err.stack || err : err, err.status || 500)
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 先判断控制器是否存在
|
// 1. 先判断控制器是否存在
|
||||||
if (!this.__MODULES__[req.app]) {
|
if (!this.__MODULES__[req.app]) {
|
||||||
if (this.__MODULES__.__error__) {
|
return res.error(`Controller [${req.app}] not found`, 404)
|
||||||
res.error(
|
|
||||||
debug ? this.__MODULES__.__error__.stack : this.__MODULES__.__error__,
|
|
||||||
500
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
res.error(`Controller [${req.app}] not found`, 404)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 默认二级路由为index
|
// 2. 默认二级路由为index
|
||||||
|
@ -28,29 +24,35 @@ export default function(req, res, next) {
|
||||||
// 3. 实例化控制器
|
// 3. 实例化控制器
|
||||||
this.__MODULES__[req.app]
|
this.__MODULES__[req.app]
|
||||||
.then(({ default: Mod }) => {
|
.then(({ default: Mod }) => {
|
||||||
var app = new Mod({ ctx: this, req, res })
|
var app,
|
||||||
var err = ''
|
err = ''
|
||||||
|
if (Mod) {
|
||||||
|
app = new Mod({ ctx: this, req, res })
|
||||||
|
|
||||||
// action模式, 则路由自动调用对应的action方法
|
// action模式, 则路由自动调用对应的action方法
|
||||||
// __main__模式, 则路由全部走__main__方法
|
// __main__模式, 则路由全部走__main__方法
|
||||||
if (this.get('routeMode') === 'action') {
|
if (this.get('routeMode') === 'action') {
|
||||||
var route = req.path.shift()
|
var route = req.path.shift()
|
||||||
var act = route + 'Action'
|
var act = route + 'Action'
|
||||||
|
|
||||||
if (app[act]) {
|
if (app[act]) {
|
||||||
return app[act].apply(app, req.path)
|
return app[act].apply(app, req.path)
|
||||||
|
} else {
|
||||||
|
err = new Error(`Route [${route}] not found`)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err = new Error(`Route [${route}] not found`)
|
if (app.__main__) {
|
||||||
|
return app.__main__.apply(app, req.path)
|
||||||
|
} else {
|
||||||
|
err = new Error('__main__() not found')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
err.status = 404
|
||||||
} else {
|
} else {
|
||||||
if (app.__main__) {
|
err = new Error(`Controller [${req.app}] load error`)
|
||||||
return app.__main__.apply(app, req.path)
|
err.status = 500
|
||||||
} else {
|
|
||||||
err = new Error('__main__() not found')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err.status = 404
|
|
||||||
return Promise.reject(err)
|
return Promise.reject(err)
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
|
Loading…
Reference in New Issue