优化中间件/路由/跨域

v1
宇天 2020-09-22 19:58:29 +08:00
parent b2c424a384
commit 38ad516e08
4 changed files with 80 additions and 87 deletions

View File

@ -36,9 +36,8 @@ function hideProperty(host, name, value) {
export default class Five {
constructor() {
hideProperty(this, '__FIVE__', Object.assign({}, init))
hideProperty(this, '__MODULES__', { __error__: null })
hideProperty(this, '__MODULES__', {})
hideProperty(this, '__MIDDLEWARE__', [])
hideProperty(this, '__INSTANCE__', {})
}
__init__() {
@ -94,63 +93,51 @@ export default class Five {
// 获取全局配置
get(key) {
try {
return new Function('o', `return o.${key}`)(this.__FIVE__)
} catch (err) {}
return this.__FIVE__[key]
}
// 加载中间件/缓存模块
// 加载中间件
// 与别的中间件用法有些不一样, 回调的传入参数中的req和res,
// 并非原生的request对象和response对象,
// 而是框架内部封装过的,可通过origin属性访问原生的对象
use(key, fn) {
if (arguments.length === 1) {
if (typeof key !== 'function') {
throw TypeError('argument 1 must be a callback')
}
this.__MIDDLEWARE__.push(key)
} else {
if (typeof key !== 'string') {
return
}
libs[key] = fn
use(fn) {
if (typeof fn === 'function') {
this.__MIDDLEWARE__.push(fn)
return this
}
throw TypeError('argument must be a callback')
}
// 预加载应用
// 预加载应用, 缓存以提高性能
preload(dir) {
var list = fs.ls(dir)
if (list) {
list.forEach(file => {
var { name } = path.parse(file)
list.forEach(item => {
var { name } = path.parse(item)
if (name.startsWith('.')) {
return
}
try {
this.__MODULES__[name] = import(file)
} catch (err) {
this.__MODULES__.__error__ = err
// 如果是目录,则默认加载index.js, 其他文件不加载
// 交由index.js自行处理, 用于复杂的应用
if (fs.isdir(item)) {
item = path.join(item, './index.js')
}
this.__MODULES__[name] = import(item).catch(err => {
return { default: null }
})
})
}
return this
}
// 注实例化对象到实例池中
// 注实例化对象到实例池中
// 与use方法不同的是, 这个会在server创建之前就已经执行
ins(name, fn) {
var _this = this
if (arguments.length === 1) {
return this.__INSTANCE__[name]
}
if (typeof fn === 'function') {
fn.call(this, this.__FIVE__, function next(instance) {
if (instance) {
_this.__INSTANCE__[name] = instance
}
})
}
install({ name, install }) {
this['$$' + name] = install.call(this, this.__FIVE__)
return this
}
// 启动http服务

View File

@ -1,11 +1,11 @@
/**
*
* @authors yutent (yutent@doui.cc)
* @date 2016-05-15 14:37:47
*
* 部分配置
* @author yutent<yutent.io@gmail.com>
* @date 2020/09/22 17:19:39
*/
'use strict'
const ENV_PROD = 'production'
const ENV_DEV = 'development'
export default {
db: {},
@ -24,27 +24,30 @@ export default {
domain: '', // cookie域, 默认等于website
port: 3000,
routeMode: 'action', // action | __main__
env: process.env.NODE_ENV === 'production' ? 'production' : 'development',
debug: process.env.NODE_ENV !== 'production', // debug模式
env: process.env.NODE_ENV === ENV_PROD ? ENV_PROD : ENV_DEV,
debug: process.env.NODE_ENV === ENV_DEV, // debug模式
smtp: {
host: 'smtp.example.com',
port: 25,
mail: 'service@example.com',
name: '系统邮件',
mail: 'no-reply@example.com',
name: 'no-reply',
passwd: ''
},
supportCredentials: false,
credentialsRule: null,
credentialsMaxAge: 0,
cors: {
enabled: false,
credentials: false,
origin: [], // ['abc.com', 'a.foo.com']
maxAge: 0
},
jwt: null, // jwt secret
regexp: {
// 常用正则
email: /^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/,
uname: /^[A-Za-z\d_]{4,16}$/,
passwd: /^[\S]{6,20}$/,
phone: /^1[34578]\d{9}$/,
passwd: /^\S{6,20}$/,
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)$/,
CN: /^[\u4e00-\u9fa5]+$/,
cn: /^[\u4e00-\u9fa5]+$/,
qq: /^\d{5,12}$/
}
}

View File

@ -7,28 +7,29 @@
import url from 'url'
export default function(req, res, next) {
var supportCredentials = this.get('supportCredentials')
var credentialsRule = this.get('credentialsRule')
var credentialsMaxAge = this.get('credentialsMaxAge')
var CORS = this.get('cors')
if (supportCredentials) {
if (CORS.enabled) {
var origin = req.header('origin') || req.header('referer') || ''
var headers = req.header('access-control-request-headers')
origin = url.parse(origin)
var { hostname, host, protocol } = url.parse(origin)
if (credentialsRule && origin.hostname) {
if (!credentialsRule.test(origin.hostname)) {
if (CORS.origin.length && hostname) {
if (!CORS.origin.includes(hostname)) {
return res.end('')
}
}
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) {
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') {
return res.end('')
}

View File

@ -6,18 +6,14 @@
export default function(req, res, next) {
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. 先判断控制器是否存在
if (!this.__MODULES__[req.app]) {
if (this.__MODULES__.__error__) {
res.error(
debug ? this.__MODULES__.__error__.stack : this.__MODULES__.__error__,
500
)
} else {
res.error(`Controller [${req.app}] not found`, 404)
}
return
return res.error(`Controller [${req.app}] not found`, 404)
}
// 2. 默认二级路由为index
@ -28,29 +24,35 @@ export default function(req, res, next) {
// 3. 实例化控制器
this.__MODULES__[req.app]
.then(({ default: Mod }) => {
var app = new Mod({ ctx: this, req, res })
var err = ''
var app,
err = ''
if (Mod) {
app = new Mod({ ctx: this, req, res })
// action模式, 则路由自动调用对应的action方法
// __main__模式, 则路由全部走__main__方法
if (this.get('routeMode') === 'action') {
var route = req.path.shift()
var act = route + 'Action'
// action模式, 则路由自动调用对应的action方法
// __main__模式, 则路由全部走__main__方法
if (this.get('routeMode') === 'action') {
var route = req.path.shift()
var act = route + 'Action'
if (app[act]) {
return app[act].apply(app, req.path)
if (app[act]) {
return app[act].apply(app, req.path)
} else {
err = new Error(`Route [${route}] not found`)
}
} 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 {
if (app.__main__) {
return app.__main__.apply(app, req.path)
} else {
err = new Error('__main__() not found')
}
err = new Error(`Controller [${req.app}] load error`)
err.status = 500
}
err.status = 404
return Promise.reject(err)
})
.catch(err => {