egg.js使用指南

JavaScript053

egg.js使用指南,第1张

官方教程 有点跳跃,很多东西没讲清楚,不太适合小白理解,特此整理、归纳一下。

打开这篇博客的正确方式是:先读一遍 官方教程 ,读不懂的可以略过,然后再带着问题来看这篇文章。然后再回去读官方文档,去理解。最终目的是理解官方文档,我的文章并不权威,只是起到帮助理解文档的作用。

答案:功能更丰富、更规范的koa

使用koa时,你要写一个项目,要往里面加很多中间件,要写脚本加载routes文件夹下面的所有路由以及model文件夹下面的所有sequelize模型,koa仅仅是一个骨架,其他的都是你来完成,自由度高,但集成度低,每创建一个新项目都要做很多重复工作。egg.js是封装了一套koa,可以理解成大礼包版koa,集成度高,可以轻松创建一个项目而不用做很多繁琐的初期工作,解放生产力,更可贵的是有一套现成的规范提供给我们,不需要我们自己再去探索一套规范,比如router放哪里,controller放哪里,需不需要service,哪些放在service等等。

根据egg.js 目录结构 先了解其项目规范,为了了解这些目录/文件是做什么,先从我们最熟悉的request讲起:

在进行下面的阅读前请保证已经理解了egg.js中的 内置对象 。

内置对象可以被方便地获取到,不过功能有限,我们可以通过egg.js的扩展(Extend)功能去进一步加强、定制框架的能力。

egg.js中有非常多新鲜的特性:“扩展”、“插件”、“多环境配置”,这些特性名称虽然不一样,但本质都是一样的:有则覆盖,无则增加。类似于 lodash中的defaults函数 ,也类似于继承。

因此,如果我们想扩展Application对象,根据egg.js规范,应该在projectDir/app/extend/下增加application.js:

以后就可以方便地调用 app.specialName 获取这个值。

Extend特性可以扩展上层框架的内置对象,而 插件 则可以扩展除router和controller之外的整个app。插件拥有自己的package.json,因此可以独立发布到npm,每个人都可以install,享用你的扩展。

如果我要为项目写一个管理微信公众号的功能,我会写一个WxService:

很多项目都可以用到这个Service,因此我会提取为一个插件,然后通过引入插件的形式去引入,我在应用中同样可以调用这个Service,等于是把插件中的文件往应用中复制了一份,和写在应用中没什么两样。

关于如何提取插件,请参见: 渐进式开发

定制自己的框架可以确定项目的技术选型、减少项目初期的工作,定制框架的思想其实和扩展内置对象、开插件是一样的,但是前置工作会比较多一些,参见: egg.js框架开发 。

这些前置工作比较重复、有固定格式,没有必要自己写,建议用骨架搭建。

当我们基于自己定制的框架framework1,并且在应用中依赖了插件plugin2、plugin3,开发了一个应用:

其中framework1直接基于egg并且内置了plugin1,此时整个app的加载顺序是怎样的呢?

加载原则总结一句话是:从被依赖到依赖。

先来分析一下,谁被依赖,谁依赖:

为了最大程度利用多核、增强Node进程健壮性,一般我们会使用PM2一类的工具,如果使用egg.js,就完全不需要担心了,egg利用cluster模块( 了解cluster原理请看这篇文章 )已经创建了一个非常稳定的多进程模型。

##### 什么是Socket.io

一个基于 Node.js 的实时应用程序框架,在即时通讯、通知与消息推送,实时分析等场景中有较为广泛的应用

##### 什么是egg-socket.io

- 对socket.io的二次封装, 增加了一些开发规范

- 增加namespace(命名空间), 可以通过配置的方式定义

- 增加middleware, 对每一次socket连接的建立、断开、消息和数据传递进行预处理

- controller, 相应socket.io的event事件

- router, 同一了socket.io的event与框架路由的处理配置方式

##### 把egg-socket.io整合到我们的egg项目中

不知道怎么搭建egg项目的翻下以前的文章

- 安装egg-socket.io

```

cnpm i egg-socket.io -S

```

- 开启插件

{app_root}/config/plugin.js

```

exports.io = {

  enable: true,

  package: 'egg-socket.io',

}

```

- 配置egg-socket.io

{app_root}/config/config.default.js

```

module.exports = appInfo =>{

  const config = exports = {

    io: {

      # namespace命名空间配置为/

      namespace: {

        '/': {

          # 预处理器中间件, 我们这里配置了一个auth, 进行权限判断, 它对应的文件是/app/io/middleware/auth.js, 这里可以配置多个文件, 用逗号隔开

          connectionMiddleware: ['auth'], #这里我们可以做一些权限校验之类的操作

          packetMiddleware: [], # 通常用于对消息做预处理,又或者是对加密消息的解密等操作

        },

      },

      # 配置redis, 非必须, 不需要的可以不配置这块, egg-socket.io内置了socket-io-redis, 在cluster模式下, 使用redis可以较为简单的实现clients/rooms等信息共享

      redis: {

        host: 'ip地址',

        prot: 6379,

        auth_pass: 123456,

        db:0,

      }

    }

  }

  省略 .....

};

```

到这里egg-socket.io已经开启并配置完毕了, 接下来我们就要编写路由和控制器了

- 先来看下egg-socket.io的项目目录结构

```

your-project-name

├── app

│  ├── extend

│  │  └── helper.js

│  ├── io

│  │  ├── controller

│  │  │  └── chat.js

│  │  └── middleware #插件中间件, 基于 socket 模型设计,处理 socket.io 请求

│  │      ├── auth.js #对应刚才配置的connectionMiddleware: ['auth']

│  └── router.js

├── config

└── package.json

```

- 先配置路由

/app/router.js

```

module.exports = app =>{

  const { router, controller, io } = app

  //http 接口, 在对应的控制器中可以直接操作socket, 非常方便

  router.get('/', controller.home.index)

  router.get('/user', controller.user.index)

 

  // socket, 指向app/io/controller/chat.js的index方法

  io.route('chat', app.io.controller.chat.index)

}

```

- 然后创建auth.js

app/io/middleware/auth.js

```

const room = "default_room"

module.exports = () =>{

    return async(ctx, next) =>{

        // 权限校验通过

        ctx.socket.emit('res', 'auth success')

        // 加入房间

        socket.join(room)

        // 放行

        await next()

        console.log('断开连接')

  }

}

```

- 最后创建聊天控制器

app/io/controller/chat.js

```

'use strict'

const Controller = require('egg').Controller

const room = 'default_room'

class ChatController extends Controller {

    async index(){

        const {app, socket, logger, helper} = this.ctx

        const id = socket.id

        // 根据id给指定连接发送消息

        nsp.sockets[id].emit('res', "hello ....")

        // 指定房间连接信息列表

        nsp.adapter.clients([room], (err, clients) =>{

            console.log(JSON.stringify(clients))

        })

        //  给指定房间的每个人发送消息

        this.ctx.app.io.of('/').to(room).emit('online', this.ctx.socket.id+ "上线了")

        // 断开连接

        this.ctx.socket.disconnect()

    }

}

module.exports = ChatController

```

- 通过调用http接口给客户端发送消息

说白了就是在http接口的控制器中发送socket消息

app/controller/home.js

```

const Controller = require('egg').Controller

class HomeController extends Controller {

  async index() {

    const {app, query} = this.ctx

    // 给谁发, socket连接的id

    const id = query.id

    const nsp = app.io.of('/')

    if(nsp.sockets[id]){

    // 通过id给指定socket连接发送消息

      nsp.sockets[id].emit('res', 'hello http....')

    }

    this.ctx.body = "发送成功"

  }

}

module.exports = HomeController

```

到这里服务端完成, 下面我们来写一个简单的socket.io客户端

```

const socket = require('socket.io-client')('http://127.0.0.1:7001')

// 连接服务端

socket.on('connect', () =>{

  console.log('connect!')

  socket.emit('chat', 'hello world!')

})

//接收消息通知

socket.on('res', msg =>{

  console.log('res from server: %s!', msg)

})

// 接收上线通知

socket.on('online', msg=>{

  console.log('online from server: %s!', msg)

})

```

到这就结束了, 有问题留言!!!

node技术成为web前端领域的主流开发工具可以说本身就是一个美丽的误会,当初这个技术被开发出来使用的时候主要是为了解决后端的问题才出现的。

今天,济南java课程培训机构http://www.kmbdqn.cn/就一起来了解一下node技术的发展历程和未来的发展趋势。

a)Node8进入LTS时代Node.js大的变化是进入Node8时代,它是一个稳定的长期支持版本(LTS),除了性能提升外,还有以下几个要点。

Async/Await支持。

其实在Node.jsv7.6就可以通过flag支持了,在node8里直接落地。

通过Async函数可以更好的进行异步流程控制,远离CallbackHell。

在Async函数里,你可以通过await调用Promise,以及通过co包裹的generator,可以说,向前是完美的Async函数,向后也完美兼容各种遗留代码,称为异步终极解决方案不为过。

ES6模块支持。

通过vue/react、webpack、babel和typescript等火爆发展,es6模块得到了广泛普及和应用,在Node.jsv8.5可以通过--experimental-modules来开启这个体验版特性。

当然,你想在Node.js更早版本里使用ES6模块,可以采用@std/esm模块。

HTTP2支持。

在Node.jsv8.8就开始默认启用了,http2对服务器端推送,多通道复用等特性,能够更好地为浏览器便利,是性能优化的利器。

b)企业级Web开发基础框架除了应用广泛的主流Web框架Koa外,Fastify也是一直劲敌,作者MatteoCollina是Node.js核心开发,Stream掌门,性能优化专家。

Fastify基于Schema优化,对性能提升极其明显。

狼叔认为这是企业级Web开发,他在这里给我们介绍了3个知名框架。

b1)Egg.js阿里开源的企业级Node.js框架Egg发布2.0,基于Koa2.x,异步解决方案直接基于AsyncFunction。

框架层优化不含Node8带来的提升外,带来30%左右的性能提升。

Egg采用的是『微内核+插件+上层框架』模式,对于定制,生态,快速开发有明显提升,另外值得关注的是稳定性和安全上,也是极为出色的。

b2)NestNest是基于TypeScript和Express的企业级Web框架。

很多人开玩笑说,Nest是像Java开发方式的,确实,Nest采用TypeScript作为底层语言,TypeScript是ES6超集,对类型支持,面向对象,Decorator(类似于Java里注解Annotation)等支持。

在写法上,保持Java开发者的习惯,能够吸引更多人快速上手。

TypeScript支持几乎是目前所有NodeWeb框架都要做的头等大事,在2017年Nest算个知名项目,值得一提。

b3)ThinkJSThinkJS是一款拥抱未来的Node.jsWeb框架,致力于集成项目佳实践,规范项目让企业级团队开发变得更加简单,更加高效。

秉承简洁易用的设计原则,在保持出色的性能和至简的代码同时,注重开发体验和易用性,为WEB应用开发提供强有力的支持。

ThinkJS是国产老牌Web框架,在2017年10月发布v3版本,基于Koa内核,在性能和开发体验上有更好的提升。

整体来看,Node.js在企业Web开发领域日渐成熟,无论微服务,还是Api中间层都得到了非常好的落地。

2017年,唯一遗憾的是Node.js在servless上表现的不太好,相关框架实践偏少。

c)不可不见的Api中间层前端越来越复杂,后端服务化,今日的前端要面临更多的挑战。

一个典型的场景就是在服务化架构里,前端面临的头痛的问题是异构API,前后端联调的时候,多个后端互相推诿,要么拖慢上线进度,要么让前端性能变得极其慢。

进度慢找前端,性能差也找前端,但这个锅真的该前端来背么?Node.js的Api中间层应用很好地解决了这个问题。

后端不想改的时候,实在不行就前端自己做,更灵活,更能应变。

透传接口,对于内网或者非安全接口,可以采用中间层透传。

聚合接口,对异构API处理非常方便,如果能够梳理model,应变更容易。

Mock接口,通过Mock接口,提供前端开发效率,对流程优化效果极其明显,比如去哪儿开发的yapi就是专门解决这个问题的。

除此之外,前端如果想做一些技术驱动的事儿,SSR(服务器端渲染)和PWA(渐进式Web应用)也是非常不错的选择。

d)新领域(深度学习、区块链等)