@skhon/hong-core v0.0.3
Hobber
基于
koa2
,采用typescript
开发的node
框架with ♥︎ by ke-fe
_ _ _ ___ _ _ _ _____ _ __
| |_| || | - | || |--.| |--.| | - || --|
| _| || | | || - || - || |--- || \\
|_| |_||_|_-_|_||____||____||_|_-_ || \\
with ♥︎ by ke-fe
版本变更说明请移步
hobber-cli脚手架使用方式
hobber-cli
安装
支持nodemon自定义参数,需要制定hobber lift
启动,示例如下
script : {
"dev": "hobber lift -e 'development'",
},
//配置选项同nodemon配置
"hobber-nodemon": {
"exec": "ts-node -T -r tsconfig-paths/register"
},
hobber
内置nodemon
默认配置为
const options = {
script: path.join(appPath, './src/index.ts'),
env: {
NODE_ENV: env,
},
ignore: [ path.join(appPath, './src/statics/') ],
watch: [
path.join(appPath, './src/'),
path.join(appPath, './package.json')
],
ext: 'js json ejs pug ts',
stdout: false,
exec: "ts-node -T"
}
hobber库开发方式
- 分别在
根目录
、core、example
执行
$ npm run install
core
目录
$ npx run build
- 根目录
$ npm run lerna
example
目录
$ npm run dev
功能及规划
- 基础版本,核心功能包含
- ✅基础
server
能力 - ✅接口代理
action -> api
- ✅
login
单点登录、hdic
登录 - ✅静态资源
- ✅
Model
工具类-Utils、S3、WebShot、UserCenter
- ✅监控数据上报
- ✅
upassport
登录 - ✅数据库(TypeOrm)
- ✅企微登录
- 🚩ssr(react)
- 🚩signterm信号处理
- 🚩纯api代理生成器
- 🚩更多。。。
工具类用法
内置Model用法(用户Model不再支持,当然可以自定义使用)
// 内置Model目前支持四种(UserCenter、S3、Utils、WebShot)
import { Model } from '@ke/hobber-core' //内置model 用户Model不再支持
Model.xxx.xxx() //有对应的TS提示
比如文件上传
// 内置默认配置
const LIANJIA_AWS_CONFIG: AWS.S3.ClientConfiguration = {
accessKeyId: 'xxxxxxx', // 脱敏
secretAccessKey: 'xxxxxxxx', // 脱敏
region: 'cn-north-1',
s3BucketEndpoint: true,
s3ForcePathStyle: true,
endpoint: 'http://storage.lianjia.com/' // 默认存储地址
}
const file = ctx.form.file
if (file) {
const ext = file.filename.split('.').pop()
const s3 = Model.S3(); // 这里可以覆盖上面的配置项
const data = await s3.uploadAsync({
Bucket: 'test',
Key: `${Date.now()}.${ext}`,
Body: file
})
data.Location //则为上传后的地址
}
全局API用法
注意:为了一些性能的提升,且保证写日志部分的正常解析,目前调用API需要手动传入ctx,不然日志和自定义responseHandler和requestHandler会报错
// 获取global类型
//用户 server/apis/index.d.ts提供,hobber会使用code generator做这个事情
import { HobberGlobal } from "/{path}/apis/index"
const hGlobal: HobberGlobal = global as HobberGlobal
//有对应ts提示,两种方式,
// 注意:为了性能的提升,目前调用API需要手动传入ctx,不然日志和自定义responseHandler和requestHandler会报错
hGlobal.API.xxx.xxx(query, {ctx})
(global as HobberGlobal).API.xxx.xxx(query, {ctx})
🧢 注意:上面使用API
的时候,在后面参数中主动传入了ctx
,之前bucky
框架不是不用传也照样能用么?
🙈 解答:因为之前我们使用async_hooks
异步钩子API
帮大家临时存下来,但这里有一定的性能消耗和内存消耗,在hobber
中我们决定移除
ctx使用
import { HobberGlobal } from "/{path}/apis/index" //用户 server/apis/index.d.ts提供
import { Context } from '@ke/hobber-core/index'
async handler (ctx: Context) {
// ctx上有对应的hobber提示
const ucid = String(parseInt(ctx.request.query.ucid) || '1000000020165056')
const agent = await (global as HobberGlobal).API.userCenter.getAgentByAgentId({
id: ucid
});
// 渲染页面, about 是对应 /views 文件夹下的文件
ctx.request.id // 有对应TS提示
ctx.response.render('agent', { agent, ucid })// 有对应TS提示
}
action 示例,可使用hobber-cli
创建
import { Context } from "@ke/hobber-core/index"
import { Model } from '@ke/hobber-core' //内置model 用户Model不再支持
export default {
// 是否需要跨域
cors: true,
// 是否页面需要登陆
needLogin: true,
async handler (ctx: Context) {
//通过 ctx.request.user 获取用户信息
const user = ctx.request.user
// 渲染页面, about 是对应 views 文件夹下的文件
const result = await ctx.checkLogin({
redirectLogin: false,
source: 'xxx',
signature: 'xxxxx'
})
// 内置model调用,有对应TS提示
const valet = await Model.UserCenter.getValetInfo({
ucid: "10000000xxxxxxxx",
env: "testing",
appid: Number(xxx)
});
ctx.response.render("about", { user, result, valet });
}
}
api 示例,可使用hobber-cli
创建
import { _i_object_any } from "@ke/hobber-core/interface/interface_base.impl";
import { _i_api_config, _i_api_fn_opt, _i_api } from '@ke/hobber-core/interface/hobber_hooks/interface_api'
import { Context } from "@ke/hobber-core/index"
export default (api: _i_api) => {
api.config = {
// 接口超时时间
timeout: 10000,
// 默认的返回值简单约定, {code: , data:, msg:} 的形式返回
// 如果是这种返回形式的话,那么通过下面参数,做接口检查
codeKey: 'code',
dataKey: 'data',
messageKey: 'msg',
successCode: 1,
// 可自定义
requestHandler (requestOptions, ctx: Context) {
return requestOptions
},
// 可自定义
responseHandler (res, ctx: Context): _i_object_any | undefined {
// res 是 node-fetch 的返回值
let errors: string = null as unknown as string
if (res.statusCode === 200) {
const json = JSON.parse(res.body)
if (json.errors) {
errors = json.errors
} else {
return json
}
}
if (errors) {
try { errors = JSON.stringify(errors) } catch (e) {}
throw new Error(JSON.stringify({ message: errors, url: res.url}))
}
},
// 接口的协议,域名,端口
base: 'https://api.github.com',
// 接口请求数据格式
// 以下可选
// multipart/form-data
// application/json
// application/x-www-form-urlencoded
contentType: 'application/x-www-form-urlencoded',
// query 参数的值是否需要 encode
queryEncode: false,
}
// 定义接口
api('searchRepositories', {
// 接口 path
uri: '{search}/repositories',
// 接口访问方式
method: 'get',
// 接口参数检查
// parameters: {
// q: api.type.string.required,
// sort: api.type.string.required,
// order: api.type.string.required
// },
})
// api(....) 继续定义下一个接口
}
// 下面的特定环境可以深度合并到上面的默认环境
// 线上环境是上面的默认环境,不要乱改哦
// 开发环境配置
export const development = api => {}
// 测试环境配置
export const testing = api => {}
service configs 复写
重写config.api.xxx
这里需要注意,如果你在
service
中重写了config.api.defaultRequestHandler
,同时又重写了某个api
下的requestHandler
,但你又想service
中重写的会生效,那么请在某个api
的requestHandler
中主动调用,例如
service示例
export const configs = (config: ServiceConfig) => {
const defaultRequestHandler = config.api.defaultRequestHandler;
config.api.defaultRequestHandler = function(options, ctx) {
options = defaultRequestHandler.call(this, options, ctx);
options.headers["x-ke-trace"] = 11111;
return options;
};
return config;
};
api示例
requestHandler (req: _i_api_fn_config, ctx: Context) {
req.headers.trace_id = 123
return this.defaultRequestHandler(req, ctx)
},
上面示例表示在service中重写了api.defaultRequestHandler
和某个具体api
的requestHandler
,这样就能两个重写都生效
🧢 注意:如果你的多个插件中都修改了传入的config
配置,比如A、B、C
中都修改了config.api.defaultRequestHandler
,并且你的插件顺序是C、B、A
,那么最后修改后的只会是A
中对应的 defaultRequestHandler
所以对于多个插件configs中都对全局统一配置进行修改,强烈不建议。
并且我们建议在service
插件中只做非做不可且相对逻辑简单的事情
config
https登录跳转https失效?
- 配置
app.ts
proxy: {
'x-forwarded-proto': 'x-ssl-header',
'x-forwarded-for': 'x-real-ip'
}
login登录
cas
用户服务项目(团队)提供的登录,目前支持B/C端hdic
楼盘字典登录general
以前的C端登录,目前废弃
cas
登录分两种体系:
export default {
enable: true, // 是否使用登录
type: 'cas', // 选择需要的登录方式
cas: {
...
env: 'production-ke', //production-lianjia 两种体系
...
},
}
登录配置中
maxAge
单位毫秒(ms
)
数据库配置
- 配置示例 http://weapons.ke.com/project/1970/wiki/page/3553
- 参考
hobber-core@0.0.18
版本记录 http://weapons.ke.com/project/1970/wiki/page/2649
如果不跳链接,直接看下面
- 数据库种类
https://github.com/typeorm/typeorm/blob/master/docs/zh_CN/connection-options.md
- 数据实体
https://github.com/typeorm/typeorm/blob/master/docs/entities.md
- 实体管理器API
https://github.com/typeorm/typeorm/blob/master/docs/entity-manager-api.md
🧢 typeorm
维持数据库链接是在当前modules
下,所以只能使用创建链接时使用的node_modules
,如果你要覆盖当前typeorm
,则hobber
内置版本的链接将无效,需要注意~
🌝 hobber-cli@0.0.15
支持创建项目中增加orm
文件,配置项见 数据库配置
🌝 hobber entity mysql/User
创建数据库实例 用法见 数据库实例
🌝 hobber model mysql/User
创建操作实例的封装 实例管理器
静态文件服务器
映射关系如下
- 我们将
statics
下默认做public
的关系映射 - 如果想自定义请在启动参数中传入,如下,会将
newstatics
下映射到newpublic
,但这种自定义情况需要注意,hobber
默认只会打包statics
下的文件,所以如果自定义,请修改提供的默认Makefile
脚本
var appPath = path.resolve(__dirname)
var app = Hobber({
appPath: appPath,
staticDir: '/newstatics',
getStaticPath: () => '/newpublic', })
`{servername}/public/*` -> `{servername}/statics/*`
自定义打印日志
hobber
内部重写console.log
和console.error
两种标准流
console.log
走的标准stdout
,同时存入当前机器日志文件console.error
走的标准stderr
,同时存入当前机器日志文件和上报kafka监控平台
日志配置
access日志可配置项:
{
filename: 'access.log', //文件名
type: 'dateFile', //日志类型,具体参考log4js官网
pattern: '-yyyy-MM-dd', //日志文件的格式pattern
alwaysIncludePattern: false, //是否始终包含pattern格式
ignore: false, //是否忽略 ['/path/path1', /\path.*/] 字符串和正则
loggingResponseBody: true, //记录response body
loggingResponseBodyLimit: Infinity, //记录body 大小限制
loggingRequestHeaders: true, //记录请求headers
formatter ({ ctx, type }) { //自定义需要记录的内容格式
return this.defaultFormatter({ ctx, type })
},
}
api日志可配置项:
{
filename: 'api.log', //文件名
type: 'dateFile', //日志类型,具体参考log4js官网
pattern: '-yyyy-MM-dd', //日志文件的格式pattern
alwaysIncludePattern: false, //是否始终包含pattern格式
loggingResponseBody: true, //记录response body
loggingRequestBody: true, //记录request body
loggingRequestHeaders: false, // 记录request headers
loggingResponseHeaders: false, //记录response headers
formatter ({ ctx, requestOptions, response }) { //自定义需要记录的内容格式
return this.defaultFormatter({ ctx, requestOptions, response })
},
}
运行多环境
hobber
内置默认三种环境即development
、testing
、production
,其中testing
对应op
的test
。
如果需要新增环境,做对应的环境配置,则在对应文件对应环境(有环境区分的文件)下做相应的环境配置导出即可,比如在preview
环境导出api
的配置
export const preview = api => {
api.config.base = 'http://api-preview.ke.com/'
}
同时需要修改run.sh
脚本配置,添加preview
{
...
if [[ -z $PROJECT_ENV ]];then
case $ENVTYPE in
"test" ) PROJECT_ENV=testing ;;
"preview" ) PROJECT_ENV=preview ;;
* ) PROJECT_ENV=production ;;
esac
fi
...
}
hobber内部链路日志
hobber采用log4js打印内部链路日志,日志支持自定义
formatter
,及其附属参数log4js
官网https://github.com/log4js-node/log4js-node
// API
api: {
filename: 'api.log', //日志名 default=api.log
loggingResponseBody: true, //是否记录返回响应body default=true
loggingRequestBody: true, //是否记录请求body default=true
loggingRequestHeaders: false, //是否记录请求headers default=false
loggingResponseHeaders: false, //是否记录响应headers default=false
},
// ACCESS
access: {
filename: 'access.log', //日志名 default=access.log
ignore: [/\/public\/.*/, '/favicon.ico'], //支持正则、字符串
loggingResponseBody: true, //是否记录响应body default=true
loggingResponseBodyLimit: 500, //响应body大小限制,超出部分记为 `'<trimmed>'`
loggingRequestHeaders: true //是否记录请求headers default=true
// 其余字段遵循 log4js 规则 https://github.com/log4js-node/log4js-node
},
// ERROR
error: {
filename: 'error.log'
},
// APPLICATION
application: {
filename: 'application.log'
}
单测
目前单测部分,hobber采用的测试build后的产物,所以如果你要运行单测查看,请
cd core && npm run build
cd .. && npm run test
监控
- 🌲 新增
watcher
监控模块(0.0.7
)
action、api、service、rewrite、redirect、login
等调用异常- 运行时机器内存、服务内存、机器
cpu
占比、服务cpu
占比 - 启动上报-机器相关信息、端口、ip、域名、npm包信息
打包
目前通过脚手架生成的产物中自带
make
脚本,该脚本只会打包server
端的代码,直接执行make
命令,会生成releases
目录,该目录下包含可执行运行的server
产物的tar
包 如果只是本地构建,直接npm run build
即可
其他ctx及其挂载功能
可借助TS的类型提示
直接
hobber
上帝群吼