Code Monkey home page Code Monkey logo

egg's Issues

初始化项目出错 read ECONNRESET

[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)

aliyun-egg需要的能力

通用安全插件、阿里云各服务插件(oss、cdn、等等常用的) @fishbar

  • egg-oss
  • egg-rds -> egg-mysql
  • egg-security
  • mts
  • ots
  • mc
  • ons

待补充

Framework Slogan

Here are a few ideas for the Egg.js framework slogan

  1. A supreme node.js framework builder to maximize productivity
  2. A modular framework builder for node.js developer
  3. The last node.js framework you ever need
  4. The node.js framework changes everything
  5. A promise to your success
  6. A node.js framework Builder
  7. next generation web framework builder for node.js (Note: compared with http://koajs.com/ slogan)
  8. Modular, opinionated, feature rich web framework for Node.js (Note: compared with http://expressjs.com/ slogan)

Singleton

刚看了 Singleton 的文档, 有几点疑问, 讨论下:

  • 我们之前的实现里面, 有很多用 Symbol + this[HELPER] 之类的方式去实现只实例化一次的对象, 这个是不是可以类似提供下简化方法?
  • 是否要考虑 loader singleton 的约定?
  • Singleton 其实是支持多实例的,那这个命名是不是不太准确?
  • 示例里面的 DataService 这个命名感觉有点问题, 会认为是放在 app/service 下, 但这个就是每个请求一个实例了.

重构 messenger

提供方法:

  1. broadcast(action, data):发送给所有的 agent / app 进程(包括自己)
  2. sendToApp(action, data): 发送给所有的 app 进程
    • 在 app 调用该方法上会发送给自己和其他的 app 进程
    • 在 agent 上调用该方法会发送给所有的 app 进程
  3. sendToAgent(action, data): 发送给 agent 进程
    • 在 app 调用该方法上会发送 agent 进程
    • 在 agent 上调用该方法会发送给 agent 自己
  4. sendRandom(action, data):
    • app 上没有该方法(现在 egg 的实现是等同于 sentToAgent)
    • agent 上回随机发送消息给一个 app 进程(由 master 来控制发送给谁)
  5. sendTo(pid, action, data): 发送给指定进程

Master 去除 loader 依赖

master 现在的 loader 会加载 config

  1. 读取 env,可以单独实现
  2. 获取 logger 的配置,master 的 logger 可以直接使用 consoleLogger,error 打到 stderr

中文文档

proxymock 改造

  • egg-proxymock -> egg-mockdata ?
  • 配合 loader #11 的改造, 支持 mock 不同的对象
  • 除了原支持的 exports.fn 方式, 增加 class 的支持, 如继承 ServiceClass 然后替换

[RFC] 抽取 passport 模型

  • egg-passport-github
  • egg-passport-weibo @shaoshuai0102
  • egg-passport-gitlab
  • egg-passport-google
  • egg-passport-taobao

RFC: passport

由于业界的 passport 已经足够简单,egg 做起来就是配置。对应应用开发者,更加是配置,基本无需编写代码就能实现。

一个应用的 authenticate 通用过程

  1. 用户会选择应用提供的其中一种 strategy 进行 authenticate 登录,如应用同时提供了 twitter 和 facebook 两种方式。
  2. 用户去 twitter 登录成功后,会返回应用网站,然后 egg-passport-twitter 插件,会使用 verify callback 来完成对统一约定 user 的封装,继续返回给 egg-passport 做后续处理。
  3. egg-passport 会触发 app.passport.verify hook,这样应用层就能做最终的核实,例如做新用户注册,老用户绑定校验等等,这里也是用户数据持久化的地方。
  4. 用户登录之后,每次访问应用都会根据 app.passport.deserializeUserapp.passport.serializeUser 来还原 session。

说明

  • 框架内置了高度抽象的 passport 插件。
  • passport-xxx 插件都需要声明依赖内置的 passport 插件。
  • passport-xxx 插件开发者只需要简单结合一下 http://passportjs.org 现有的模块,就可以快速完成一个网站的 authenticate 接入。
    如要对接 Twitter 的 oauth,那么只需要引入 passport-twitter,并实现一个 passport-twitter 插件即可。

统一 user 字段约定

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 的其他字段,每个平台提供的都不太一样,需要各种区别

passport 配置

// config/config.${env}.js
exports.passport = {
  twitter: {
    consumerKey: 'your-consumer-key',
    consumerSecret: 'your-consumer-secret',
    // 更多配置请查看 passport-twitter 插件
  },
};

应用需要关注的3个用户数据处理 hooks

// 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) {

  });
};

术语整理

将现有用到的术语整理出来,保持统一,写文档和代码都好理解

egg-core

Loader

做到灵活性,扩展性强。

API

loader 只提供原子粒度的 API,由框架来自行组织

Env

  • getServerEnv
  • getEggPaths
  • getLoadUnits
  • getAppname

Low Level API

  • loadFile
  • loadToApp
  • loadToContext
  • loadExtend

High Level API

  • loadPlugin
  • loadConfig
  • loadController
  • loadMiddleware
  • loadApplicationExtend
  • loadContextExtend
  • loadRequestExtend
  • loadResponseExtend
  • loadHelperExtend
  • loadCustomApp
  • loadCustomAgent
  • loadService

和插件的关系

插件需要用到 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 插件

load unit

每个加载单元的目录结构都是类似的,框架、插件、应用的路径都是称为 loadDir。

|- app
  |- extend
  |- service
  |- controller
  |- middleware
  `- router.js
|- config
  |- config.js
  `- plugin.js
|- agent.js
`- app.js

LoaderOptions

  • directory: null,
  • target: null,
  • ignore: undefined,
  • lowercaseFirst: false,
  • initializer: null,
  • call: true,
  • override: false,
  • inject: undefined,

Action

  • 去除 loading
  • app.js/agent.js 支持返回一个 promise #51
  • 调整 console
  • 去除 lib/core 潜规则?
  • 去除 eggPath 和 customEgg 参数
  • 增加 strict 模式 #52

Core

egg-core 是包含了 loader 和应用初始化的功能,简单理解就是一个有目录约定的 koa,初始化包括了 loader。

  • loader
  • ready
  • logger
  • router

egg 就像其他框架一样只需要继承 egg-core 就可以直接使用


@atian25

嗯, 只需提供一个机制给框架开发者扩展, 如集团那边是有 proxy, 其他开发者可以定义:

this.db.xxx -> app/db/xxx.js
this.filters.xxx -> app/filters/xxx.js

Label

增加不同类别的 label

  1. semver: major, semver: minor, semver: patch
  2. core
  3. plugin: security,
  4. tools: egg-mock, egg-bin
  5. feature, fix, refactor, improve, test, doc, release, discussion

1.0 Milestone

Core

Tool

Plugin

framework

  • aliyun-egg

Doc

  • egg README
  • 其他 README 规范
  • CONTRIBUTING
  • Tutorial
  • benchmark @fengmk2

release ready

开发方式

  1. 先提交源码保证可以用,依赖层级比较深。
  2. 补测试,测试的目录接口和源码保持一致。
  3. 新仓库先提交空的 README,提交 PR 完成功能,补测试需要测试通过

Example cookie does not work

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)

egg-mock

egg-mock is a mock server and a list of mocked API with egg-mock plugin.

  • mm.app
  • mm.cluster
  • API
  • test with egg

统一多实例的插件创建方式,文档化提供最佳实践

类似 oss / mysql 等都可能存在需要创建多个实例的需求,在插件里面现在有两种实现方式:

  1. 新增一个 createInstance 方法来自定义创建。
  2. 配置支持数组形式,然后通过 this.mysql.db1 来获取

对外的插件最好有一个统一的形式。特别是 aliyun-egg 估计会遇到挺多类似的问题

Deadline -- 8月底前必须完成的事.

做下备忘, 然后定下时间点和分猪肉吧.

我们还剩下不到 15 天了, 包括周六日.

  • 类库
    • 完成 egg 的所有核心库
    • egg 插件检查 (文档, 注释英文, 更新依赖版本, 发布 1.x 版本, public ) #5
    • 框架
      • aliyun-egg 还搞么?
    • example
  • 数据收集 @fengmk2 @gxcsoccer
    • benchmark
    • 业务使用情况统计, 应用数/进程数 (先放到内网 issue, 并走数据披露流程)
  • 文档编写
    • 编写使用文档, 参考 chair 文档
      • 列出大纲 (#55) @atian25
      • 术语整理
      • 文档列表(待分猪肉)
    • 文档翻译为 English @mattma
    • Web 规范文档的翻译 @mattma
      • 是否需要补充 logger 的规范进去?
      • #12
    • Api 文档构建 #34
    • jsconf ppt 编写 ( @atian25 本周出大纲 review )
  • 官网建设 (已出原型图, 使用 hexo 发布, @popomore)
  • 清理 milestone, #5

cc @eggjs/core @eggjs/contributor

[RFC] egg-opentracing

分布式链路追踪是当今微服务架构中必不可少的组成部分,一个请求穿插于各个应用系统、中间件、数据库之间,通过 tracing 就能知道整个请求的链路以及各部分的耗时。Egg 会基于开放的 opentracing 来实现这个功能。

概念

Trace:一个 Trace 代表在微服务架构中的一次链路请求,可能经过一个或多个微服务应用。

Span:一个 span 代表系统中具有开始时间和执行时长的逻辑运行单元,一个 Trace 会包含多个 Span。

SpanContext:代表一个 Span 的信息,比如 TraceId,spanId,以及该 Span 的相关信息。注意:这个和 egg 的 ctx 没有关系。

Baggage:还有一些信息也在 SpanContext 中,我们称之为 Baggage,这些信息会在整个 Trace 中传递。

Tag:Span 中用来识别 span 的一些信息,比如

  • error
  • component: httplib, jdbc, mongoose
  • span.kind: client, server
  • http.url
  • http.method
  • http.status_code
  • framework
  • peer.hostname

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();

定义 Carrier

上面使用到了 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'),
  },
};

定义 Collector

还需要定义一个收集器

// 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

确定 Release 规则

背景

Egg 参与人员过多,仓库过多,经常会遇到某个人没有某仓库的发布权限。

Release 时会修改版本和更新 changelog,这个也需要 review。

目标

  1. Changelog 可 review
  2. npm 自动发布
  3. 锁定 master 目录不允许提交

方案

锁定 master 目录不允许任何人提交,并添加合并检测(review+2,travis 和 codecov 通过)。

Release 时本地修改版本和 changelog 后提交 PR,review 后合并。

Travis 根据 commit 信息判断是否 release(非 PR,master 分支,切 commit 匹配),通过 eggjs 账号 发布到 npm。

Action

  • 支持 travis 发布 npm 包,还需要自动 push tag
  • “本地生成 changelog 和版本”有工具支持,保证生成格式一致
  • 文档更新
  • 确定 commit 信息 chore(release): release 1.0.0
  • 自动更新 github release

Updated at 2017-02-09


screenshot 2016-08-16 8 25 51

以后所有的仓库都需要这样配置,不允许直接 push 到 master。但是 release 的时候还有一步需要 push,这个规则需要明确下。

egg-loader

关于 loader 有几个问题,需要先确定下

  • 运行环境及其名称,是否还是这几个 prod, test, default, local, unittest
  • 运行环境如何确定,除了 process.env.NODE_ENV
  • 是否还需要支持 framework 封装这个功能?

先想到这些,后面有再补充

Frontend send ajax request to Egg has an error of CORS or OPTIONS 405 Method Not Allowed

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:

screen shot 2016-08-14 at 9 57 59 am

Error on terminal console

screen shot 2016-08-14 at 10 02 38 am

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.