@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 installcore目录
$ npx run build- 根目录
$ npm run lernaexample目录
$ 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 buildcd .. && 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上帝群吼