eggjs / egg Goto Github PK
View Code? Open in Web Editor NEW🥚 Born to build better enterprise frameworks and apps with Node.js & Koa
Home Page: https://eggjs.org
License: MIT License
🥚 Born to build better enterprise frameworks and apps with Node.js & Koa
Home Page: https://eggjs.org
License: MIT License
https://nodejs.org/api/console.html#console_new_console_stdout_stderr
Console is a class.
增加不同类别的 label
// app.js
module.exports = app => new Promise(resolve => {
doAsync(resolve);
});
or
module.exports = async function() {
await doAsync();
};
[test] egg-init --type simple showcase
[egg-init] /Users/xx/test/showcase is not exists, now create it.
[egg-init] dest dir is /Users/xx/test/showcase
Error: read ECONNRESET
at exports._errnoException (util.js:896:11)
at TLSWrap.onread (net.js:556:26)
关于 loader 有几个问题,需要先确定下
prod
, test
, default
, local
, unittest
?process.env.NODE_ENV
先想到这些,后面有再补充
badgeboard 面板上能加上各个组件的说明么?
我们大多数业务都是基于数据库操作,希望官方能提供一个基于数据库的标准CRUD操作例子,大家通过标准example比较容易上手,感谢;
给 example 加上测试,CI 里面跑一下,保证示例的正确性。
egg-proxymock
-> egg-mockdata
?exports.fn
方式, 增加 class 的支持, 如继承 ServiceClass 然后替换在 strict 模式下部分验证将 warn 改成 error
类似 oss / mysql 等都可能存在需要创建多个实例的需求,在插件里面现在有两种实现方式:
this.mysql.db1
来获取对外的插件最好有一个统一的形式。特别是 aliyun-egg 估计会遇到挺多类似的问题
alinode won't delete the log files, egg-alinode plugin should delete 7 days ago log files.
Here are a few ideas for the Egg.js framework slogan
刚看了 Singleton 的文档, 有几点疑问, 讨论下:
Symbol + this[HELPER]
之类的方式去实现只实例化一次的对象, 这个是不是可以类似提供下简化方法?https://github.com/eggjs/egg/blob/master/lib/core/app/extend/context.js#L207
方便获取自定义 logger,并且自动填充 ctx 信息,就如 ctx.logger 一样。
{{ i18n
Hello ${user.name}, how are you today?}}
master 现在的 loader 会加载 config
把这个更新到文档里,作为一个规范
分布式链路追踪是当今微服务架构中必不可少的组成部分,一个请求穿插于各个应用系统、中间件、数据库之间,通过 tracing 就能知道整个请求的链路以及各部分的耗时。Egg 会基于开放的 opentracing 来实现这个功能。
Trace:一个 Trace 代表在微服务架构中的一次链路请求,可能经过一个或多个微服务应用。
Span:一个 span 代表系统中具有开始时间和执行时长的逻辑运行单元,一个 Trace 会包含多个 Span。
SpanContext:代表一个 Span 的信息,比如 TraceId,spanId,以及该 Span 的相关信息。注意:这个和 egg 的 ctx 没有关系。
Baggage:还有一些信息也在 SpanContext 中,我们称之为 Baggage,这些信息会在整个 Trace 中传递。
Tag:Span 中用来识别 span 的一些信息,比如
Carrier:在微服务架构中,两个应用之前会通过不同的协议进行通讯,但是 opentracing 是无法感知的,所以定义了 Carrier 这个概念,他通过 Inject 和 Extract 和 SpanContext 之前进行互相转换,然后 Carrier 可以在协议中传递。比如 HTTP 请求,SpanContext 通过 Inject 设置 HTTPCarrier(转换成请求头),在请求接收方通过 Extract 将 HTTPCarrier 提取成 SpanContext。
Collector:我们通过 Collector 收集每个 span 的具体信息,然后记录,可以通过日志的方式或请求上报的方式。
Egg 提供 ctx.tracer
实例作为一次 Trace,下面按照一个微服务应用整个请求周期描述各个 API
比如收到了一个 HTTP 请求,在 server 入口应该
// app/middleware/meta.js
module.exports = () => {
return async function meta(ctx, next) {
// 从 http header 获取 span 上下文
const spanContext = ctx.tracer.extract('HTTP', ctx.header);
// 创建 span 时指定父级 span
const span = ctx.tracer.startSpan('http_server', { childOf: spanContext });
await next();
span.finish();
};
}
比如发起一个 RPC 请求,需要在 RPC 客户端
const span = ctx.tracer.startSpan('rpcclient');
const rpcCarrier = {};
ctx.tracer.inject(span.context, 'RPC', rpcCarrier);
ctx.rpcclient.invoke(data, rpcCarrier);
span.finish();
上面使用到了 inject 和 extract 其实是需要这里提前定义的
// lib/http_carrier.js
module.exports = class HttpCarrier {
inject(spanContext) {
// 转换
return header;
}
extract(header) {
// 转换
return spanContext;
}
}
// config/config.default.js
exports.opentracing = {
carrier: {
'HTTP': require('../lib/http_carrier'),
},
};
还需要定义一个收集器
// lib/log_collector.js
module.exports = class LogColletor {
collect(spanContext) {
this.ctx.logger.write(this.format(spanContext));
}
}
// config/config.default.js
exports.opentracing = {
collector: {
log: require('../lib/log_collector'),
},
};
Egg 的 Tracer 和 Span 对象都是 opentracing 的一个实现,但你也可以通过覆盖的方式来实现。
// config/config.default.js
exports.opentracing = {
globalTracer: YourTracer,
};
Zipkin, Dapper, HTrace, X-Trace
提供方法:
broadcast(action, data)
:发送给所有的 agent / app 进程(包括自己)sendToApp(action, data)
: 发送给所有的 app 进程
sendToAgent(action, data)
: 发送给 agent 进程
sendRandom(action, data)
:
sendTo(pid, action, data)
: 发送给指定进程egg-mock is a mock server and a list of mocked API with egg-mock plugin.
我们是大写分隔,如果是类就首字母大写还是下划线分隔?
Running cookie example, I clicked on "remember" checkbox, then submit. It routes to /remember
route, none of the logic in remember route is being run due to error secret is missing
. See the full error log
2016-08-11 23:52:47,376 INFO 10862 [-/::1/-/8ms GET /] status 200 (rt: 8ms)
2016-08-11 23:52:49,389 WARN 10862 [-/::1/-/15ms POST /remember] nodejs.ForbiddenError: secret is missing
at Object.module.exports.throw (/Users/mattma/Desktop/egg/egg/node_modules/koa/lib/context.js:91:23)
at Object.context.assertCSRF.context.assertCsrf (/Users/mattma/Desktop/egg/egg/node_modules/koa-csrf/index.js:69:30)
at Object.csrf (/Users/mattma/Desktop/egg/egg/node_modules/egg-security/lib/middlewares/csrf.js:39:12)
at next (native)
at Object.<anonymous> (/Users/mattma/Desktop/egg/egg/node_modules/koa-compose/index.js:29:12)
at next (native)
at onFulfilled (/Users/mattma/Desktop/egg/egg/node_modules/co/index.js:65:19)
at /Users/mattma/Desktop/egg/egg/node_modules/co/index.js:54:5
at Object.co (/Users/mattma/Desktop/egg/egg/node_modules/co/index.js:50:10)
at Object.toPromise (/Users/mattma/Desktop/egg/egg/node_modules/co/index.js:118:63)
做到灵活性,扩展性强。
loader 只提供原子粒度的 API,由框架来自行组织
Env
Low Level API
High Level API
插件需要用到 loader 功能需要增加一个 loader 插件,比如 db 的功能
|- app
`- db
`- a.js
新增 egg-loader-db 插件
// app.js
module.exports = function(loader) {
app.loader.loadToApp('app/db', 'db');
};
db 插件直接依赖 egg-loader-db 插件
每个加载单元的目录结构都是类似的,框架、插件、应用的路径都是称为 loadDir。
|- app
|- extend
|- service
|- controller
|- middleware
`- router.js
|- config
|- config.js
`- plugin.js
|- agent.js
`- app.js
egg-core 是包含了 loader 和应用初始化的功能,简单理解就是一个有目录约定的 koa,初始化包括了 loader。
egg 就像其他框架一样只需要继承 egg-core 就可以直接使用
嗯, 只需提供一个机制给框架开发者扩展, 如集团那边是有 proxy, 其他开发者可以定义:
this.db.xxx -> app/db/xxx.js
this.filters.xxx -> app/filters/xxx.js
将现有用到的术语整理出来,保持统一,写文档和代码都好理解
Egg 参与人员过多,仓库过多,经常会遇到某个人没有某仓库的发布权限。
Release 时会修改版本和更新 changelog,这个也需要 review。
锁定 master 目录不允许任何人提交,并添加合并检测(review+2,travis 和 codecov 通过)。
Release 时本地修改版本和 changelog 后提交 PR,review 后合并。
Travis 根据 commit 信息判断是否 release(非 PR,master 分支,切 commit 匹配),通过 eggjs 账号 发布到 npm。
chore(release): release 1.0.0
Updated at 2017-02-09
以后所有的仓库都需要这样配置,不允许直接 push 到 master。但是 release 的时候还有一步需要 push,这个规则需要明确下。
schedule 的结构是
{
'filepath': exports
}
可以直接继承 FileLoader 来写,https://github.com/eggjs/egg-core/blob/master/lib/loader/file_loader.js
在 Github 如何使用 puml
看能否作为 transport 基类
egg与微信集成有plugin么? 希望提供,感谢
通用安全插件、阿里云各服务插件(oss、cdn、等等常用的) @fishbar
待补充
由于业界的 passport 已经足够简单,egg 做起来就是配置。对应应用开发者,更加是配置,基本无需编写代码就能实现。
app.passport.verify
hook,这样应用层就能做最终的核实,例如做新用户注册,老用户绑定校验等等,这里也是用户数据持久化的地方。app.passport.deserializeUser
和 app.passport.serializeUser
来还原 session。ctx.user
是一个 getter,真实数据来自于 ctx.state.user
。
每个 passport-xxx 插件都需要按照约定封装一个 user。
user.provider
: 用户信息来自那种登录策略,如 twitter, weibo, facebook,这样就能通过此字段读取 user.profile
信息了。一般都是自动填充user.id
: 用户 id,字符串user.name
: 用户名user.displayName
: 昵称user.token
: oauth1 的话必须提供user.tokenSecret
: oauth1 的话必须提供user.accessToken
: oauth2 的话必须提供user.refreshToken
: oauth2 的话必须提供user.profile
: profile 的其他字段,每个平台提供的都不太一样,需要各种区别// config/config.${env}.js
exports.passport = {
twitter: {
consumerKey: 'your-consumer-key',
consumerSecret: 'your-consumer-secret',
// 更多配置请查看 passport-twitter 插件
},
};
// app.js
module.exports = app => {
// 1. 核实登录用户信息,自行判断是否需要做数据调整,
// 也可以在这里由应用自身统一 user 的数据结构,并且保存到数据库。
// - 必须返回核实后的 user,即 verifiedUser,数据结构可以由应用自行统一约定
// - 核实失败,throw 一个带有 status = 401 的 error 异常
// - 其他异常,将会当作服务端内部异常处理
//
// passport-xxx 插件已经按约定生成了 user 数据,应用可以在此做最终的用户校验,并且做数据持久化
// 在 strategy.authenticate 成功之后调用
app.passport.verify(function* (ctx, user) {
});
// 自行处理经过 verify 后的 verifiedUser 数据如何序列化到 session
// 在 http 请求结束阶段,保存数据到 session 之前调用
app.passport.serializeUser(function* (ctx, verifiedUser) {
// you can store profile and handle token here
});
// 根据 sesssion 中的 sessionUser 信息,还原出 verifiedUser
// 在 http 请求开始阶段,还原 session 之后调用
app.passport.deserializeUser(function* (ctx, sessionUser) {
});
};
大部分都叫 logrotator,而我们是 logrotater
做下备忘, 然后定下时间点和分猪肉吧.
我们还剩下不到 15 天了, 包括周六日.
cc @eggjs/core @eggjs/contributor
使用 https://github.com/istanbuljs/nyc 替换 istanbul
Goal: Egg works as simple RESTful api server, Frontend communicates with Egg via Ajax requests. Browser (Chrome latest) has Cross Origin enabled by default. Egg enabled CORS, frontend sends a request and need to get the payload back from Egg.
I have created an Angular frrontend and trying to talk to Egg ONLY via RESTful api. But I run into an issue of CORS. This is the error message from browser console:
XMLHttpRequest cannot load http://localhost:7001/api/user. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access.
I am not sure that it is an error from front end, or egg, or its plugins: egg-rest, egg-cors, or just an User error.
Here is how you can duplicate the issue.
1st Use [examples/restful_api] , then enabled cors
plugins at [here](https://github.com/eggjs/egg/tree/master/examples/restful_api)(https://github.com/eggjs/egg/blob/master/examples/restful_api/config/plugin.js#L3)
// restful_api/config/plugin.js
exports.cors = true;
exports.rest = true;
Note: it works on curl
with/without cors=true
. and all CRUD operation works as expected.
2nd Frontend ajax request: Here I included a simple HTML with jquery ajax caller.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<script>
jQuery.ajax({
url: "http://localhost:7001/api/user",
type: "GET",
contentType: "application/json",
async: true,
crossDomain: true,
beforeSend: function(xhr) {
xhr.setRequestHeader('X-Test-Header', 'test-value');
},
success: function( users ) {
console.log('users: ', users)
}
});
</script>
</body>
</html>
3rd - Load up in the browser, I see the error below:
Error on terminal console
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.