《前端之路》--- 重温 Egg.js

在 nodejs 发展日益健壮和稳定的情况下,我们在日常的开发中使用 node 已经是一件非常常规的事情了,那么对于我们必要的掌握一个服务端框架还是非常有必要的。下面我们就开始吧。

一、基础功能

1.1、目录结构

在了解目录结构之前,我们需要对 mvc 的编程模式,进行一个理解。

  • M =》 Model(模型) 是处理应用程序数据逻辑的部分,主要是和数据库打交道。
  • V =》 View(视图) 是作为视图展示使用,如果没有这部分的需求的化, view 这一个层面的内容是可以被省略的。
  • C =》 Controller(控制器) 是应用程序中处理与用户交互的部分,通常是为了 视图需要的数据做准备,并向 Model 发送数据(get、post) 等
  • S =》 Service(服务) 在实际应用中,Controller 一般不会自己产出数据,也不会包含复杂的逻辑,复杂的过程应抽象为业务逻辑层 Service

但是在一些 mvc 框架的论坛中,也有一部分的声音是说希望,业务层面的架构是一个 Thin Controller Fat Model and no need Service 那么在这样的一个出发点上来将的话,我们可以在后面实际的业务中去不断尝试。

egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
│ ├── router.js // 路由设置
│ ├── controller // 控制器
│ └── home.js
│ ├── service (可选) // 服务
│ └── user.js
│ ├── middleware (可选) // 中间件
│ └── response_time.js
│ ├── schedule (可选) // 用于定时任务
│ └── my_task.js
│ ├── public (可选) // 静态资源文件
│ └── reset.css
│ ├── view (可选) // 模板视图
│ └── home.tpl
│ └── extend (可选) // 集成功能小插件
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config // 必要的核心配置
│ ├── plugin.js // 插件配置
│ ├── config.default.js // 默认基础配置
│ ├── config.prod.js // 生产环境
│ ├── config.test.js (可选) // 测试配置
│ ├── config.local.js (可选) // 本地配置
│ └── config.unittest.js (可选) // 待定
└── test // 测试需要
├── middleware
└── response_time.test.js
└── controller
└── home.test.js

目录结构

  • app/router.js 用于配置 URL 路由规则
  • app/controller/** 用于解析用户的输入,处理后返回相应的结果
  • app/service/** 用于编写业务逻辑层
  • app/middleware/** 用于编写中间件
  • app/public/** 用于放置静态资源
  • app/extend/** 用于框架的扩展
  • config/config.{env}.js 用于编写配置文件
  • config/plugin.js 用于配置需要加载的插件
  • test/** 用于单元测试
  • app.js 和 agent.js 用于自定义启动时的初始化工作

1.2、内置对象

我们在看 egg 的内置对象的时候,我们先看下 koa 的内置对象,application、context、request、response。

再对比下 egg 的内置对象: 包括从 Koa 继承而来的 4 个对象(Application, Context, Request, Response) 以及框架扩展的一些对象(Controller, Service, Helper, Config, Logger)

1.2.1、Application

Application 是一个全局对象,上面挂载了这个框架常用到的 全局方法和对象。

1.2.2、Context

Context 是一个请求级别的对象,最常见的 Context 实例获取方式是在 Middleware, Controller 以及 Service 中,例如:

// controller
class HomeController extends Controller {
async index() {
const { ctx } = this;
ctx.body = 'hi, egg, ss';
}
}
1.2.3、Request

Request 是一个请求级别的对象,继承自 Koa.Request。封装了 Node.js 原生的 HTTP Request 对象,提供了一系列辅助方法获取 HTTP 请求常用参数。

// app/controller/user.js
class UserController extends Controller {
async fetch() {
const { app, ctx } = this;
const id = ctx.request.query.id;
ctx.response.body = app.cache.get(id);
}
} // 但是如果 需要注意的是,获取 POST 的 body 应该使用 ctx.request.body,而不是 ctx.body. 所以我们在获取 请求对应参数的时候均采用 ctx.request.query 或者 ctx.request.body 的方式.
1.2.4、Response

Response 是一个请求级别的对象,继承自 Koa.Response。封装了 Node.js 原生的 HTTP Response 对象,提供了一系列辅助方法设置 HTTP 响应。

1.2.5、Controller

框架提供了一个 Controller 基类,这个基类包括了一些常用的属性: ctx、app、config、service、logger 等

const Controller = require('egg').Controller;

class TestController extends Controller {
async index() {
const { ctx, app, config, service, logger } = this;
ctx.body = 'test';
}
} module.exports = TestController;
1.2.6、Service

框架提供了一个 Service 基类, Service 基类的属性和 Controller 基类属性一致,访问方式也类似

const Service = require('egg').Service;

class TestService extends Service {
index() {
const { ctx } = this;
return ctx.request.query;
}
} module.exports = TestService;
1.2.7、Helper

Helper 用来提供一些实用的 utility 函数 ( 工具函数 ) ,可以在 Context 的实例上获取到当前请求的 Helper(ctx.helper) 实例。 其中我们还可以自定义 helper 方法,如下:

// Demo
// app/extend/helper.js
module.exports = {
upperCase(str) {
return str.toUpperCase();
}
};
1.2.8、Config

我们可以通过 app.config 从 Application 实例上获取到 config 对象,也可以在 Controller, Service, Helper 的实例上通过 this.config 获取到 config 对象。 被创建出来的原则就是希望,配置和代码分离的原则。

1.2.9、Logger

日志系统包含了 四大层面的 日志对象, 分别是 App Logger、App CoreLogger、Context Logger、Context CoreLogger、Controller Logger & Service Logger

这些从 app、context 、logger、service 等各个层面都提供对应的 debug 方法,这些方法中包括

  • logger.debug()
  • logger.info()
  • logger.warn()
  • logger.error()

后需在开发中使用到,再具体介绍每一部分的功能。

1.3、运行环境

通过 config/env 文件指定对应的环境,但是一般推荐使用 构建工具来生成这个文件,那么我们看下这个文件里面的内容是什么样子的

//  config/env
prod
// 对,就是这么简单。

在 Koa 中我们通过 app.env 来进行环境判断,app.env 默认的值是 process.env.NODE_ENV。但是在 Egg(和基于 Egg 的框架)中,配置统一都放置在 app.config 上,所以我们需要通过 app.config.env 来区分环境,app.env 不再使用。

1.4、配置

框架提供了强大且可扩展的配置功能,可以自动合并应用、插件、框架的配置,按顺序覆盖,且可以根据环境维护不同的配置。合并后的配置可直接从 app.config 获取。

配置文件:

  • config.default.js ---默认配置文件,一般也作为开发环境使用
  • config.prod.js --- 生产环境配置文件,会覆盖默认配置文件的同名配置
  • config.unittest.js --- 单元测试, 测试环境
  • config.local.js --- 本地开发环境,额外于 默认配置。

1.5、中间件

这里简单介绍下,如何编写 中间件 和如何使用 中间件。

1.5.1、如何编写中间件

从文件夹规则来说,我们编写的自己的中间件一般都会放在 app/middleware/ xxx.js 具体的 Demo 如下:

// egg 的中间件
// 基于 洋葱圈模型
// 和 koa 的中间件的构成差不多,只不过 egg 在外面包裹了一层
module.exports = options => {
return async function toLowerCase(ctx, next) {
await next();
const result = ctx.request.query;
ctx.body = result;
};
};
// koa 的中间件
function log(ctx) {
console.log(ctx.method, ctx.header.host);
} module.exports = function() {
return async function(ctx, next) {
next();
await log(ctx);
};
};
1.5.2、如何使用中间件

在开始问如何使用中间件的时候,我们要清除一个问题就是我们往往在什么时候需要用到中间件、怎么用的问题,下面就简单介绍下。

  • 在应用中使用中间件
// config.default.js
module.exports = {
// 配置需要的中间件,数组顺序即为中间件的加载顺序
middleware: [ 'gzip' ], // 配置 gzip 中间件的配置
gzip: {
threshold: 1024, // 小于 1k 的响应体不压缩
},
};
  • 在框架和插件中使用中间件
// app.js
module.exports = app => {
// 在中间件最前面统计请求时间
app.config.coreMiddleware.unshift('report');
}; // app/middleware/report.js
module.exports = () => {
return async function (ctx, next) {
const startTime = Date.now();
await next();
// 上报请求时间
reportTime(Date.now() - startTime);
}
}; // 核心方法是 app.config.coreMiddleware.unshift('report')
  • router 中使用中间件
module.exports = app => {
const gzip = app.middleware.gzip({ threshold: 1024 });
app.router.get('/needgzip', gzip, app.controller.handler);
};
  • 框架本身自带中间件
// 修改一些初始化的配置
// config/config.default.js
module.exports = {
bodyParser: {
jsonLimit: '10mb',
},
};
1.5.3、中间件的通用配置
  • enable 是否开启使用中间件
  • match 设置只有符合某些规则的请求才会经过这个中间件
  • ignore 设置符合某些规则的请求不经过这个中间件
module.exports = {
bodyParser: {
enable: fasle // 不开启使用 bodyParser 中间件
},
gzip: {
match: '/static' // 只压缩 /static 目录下的文件
},
apiAgent: {
ignore: /^\/api/ // 只用 /api 的请求路径才不会使用 apiAgent 中间件
}
};

1.6、路由

Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系, 框架约定了 app/router.js 文件用于统一所有路由规则

// demo
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/news', controller.news.list);
router.get('/user/:id', controller.test.user);
};

router 提供的访问方法

  • router.head - HEAD
  • router.options - OPTIONS
  • router.get - GET
  • router.put - PUT
  • router.post - POST
  • router.patch - PATCH
  • router.delete - DELETE
  • router.redirect --- 这里重点提示下 redirect 重定向,可以对 URL 进行重定向处理,比如我们最经常使用的可以把用户访问的根目录路由到某个主页。

router 有哪些使用方式?

主要列举2中方式:

  • 最简单的一种,直接 router.method('/url', controller)
router.verb('path-match', app.controller.action);
  • 最复杂的一种方式
router.verb('router-name', 'path-match', middleware1, ..., middlewareN, app.controller.action);

// router-name 是指路径别名
// middleware 是指 中间件
// path-match 是指 路由 url

如何使用 RESTful 风格的 URL 定义

// 定义
// router.js
router.resources('posts', '/api/posts', controller.posts);
// controller/posts.js
exports.index = async ctx => {
ctx.body = {
success: true,
data: [1, 2, 34]
};
};

访问 http://127.0.0.1:7001/api/posts 即可

这里需要仔细一点,查看关于 restful 的 使用方法,需要对 restful 有一个基本对理解。

二、总结

其实整篇文章,写到这里已经初步对于 egg 已经有了一个大概的了解了,那么后续我猜应该还会有对应的实际的写项目的文章吧(希望有时间和经历来写)

GitHub 地址:(欢迎 star 、欢迎推荐 : )

《前端之路》 - 重温 EggJS

《前端之路》--- 重温 Egg.js的更多相关文章

  1. 《前端之路》之 Javascript 模块化管理的来世今生

    目录 第二章 - 04: Javascript 模块化管理的来世今生 一.什么是模块化开发 1-1.模块化第一阶段 1-2.封装到对象 1-3. 对象的优化 二.模块化管理的发展历程 2-1.Comm ...

  2. 《前端之路》之二:数据类型转换 && 隐式转换 || 显式转换

    目录 02:数据类型转换 && 隐式转换 || 显式转换 02:数据类型转换 && 隐式转换 || 显式转换 在上一个章节中,我们介绍了 JavaScript 的基本的 ...

  3. 搭建Node.js的Web框架egg.js

    1 egg.js的Request处理流程: 2. 使用nodejs下载egg.js框架 (1)现在nodejs中全局安装egg-init 即在nodejs安装根目录下执行  : d:cd nodejs ...

  4. 前端迷思与React.js

    前端迷思与React.js 前端技术这几年蓬勃发展, 这是当时某几个项目需要做前端技术选型时, 相关资料整理, 部分评论引用自社区. 开始吧: 目前, Web 开发技术框架选型为两种的占 80% .这 ...

  5. Node.js框架之Egg.js

    Node.js是我前段时间接触的一个JavaScript的服务端语言,感觉还是挺有意思的. 也许有人说,你学这么多,学的过来吗?或者说学的太多,专而不精,有必要这样吗? 其实,我个人认为,自从我进入I ...

  6. egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名

    egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名 评论:10 · 阅读:8437· 喜欢:0 一.需求 二.CSRF 校验 三.通过 form 表单上传文件 四.通过 ...

  7. 基于 Egg.js 框架的 Node.js 服务构建之用户管理设计

    前言 近来公司需要构建一套 EMM(Enterprise Mobility Management)的管理平台,就这种面向企业的应用管理本身需要考虑的需求是十分复杂的,技术层面管理端和服务端构建是架构核 ...

  8. vue+egg.js+mysql一个前后端分离留言板项目

    一.前序 我相信每个人前端搬运工和我想法都是一样的,都有一个做全栈的梦,无奈面对众多的后台语言,却不从下手,今天由我来带你们潜入全栈的门槛,注意是门槛.能不能学的会后面的内容全靠坚持了. 我今天主要做 ...

  9. 【前端芝士树】Vue.js面试题整理 / 知识点梳理

    [前端芝士树] Vue.js 面试题整理 MVVM是什么? MVVM 是 Model-View-ViewModel 的缩写. Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑. ...

随机推荐

  1. Mybatis Generator逆向工程的使用

    一.在 idea 中使用 mybatis generator 逆向工程 1.在IDEA上创建maven工程. 2.在pom.xml中配置MyBatis逆向工程插件 <!--MyBatis自动生成 ...

  2. [GX/GZOI2019]与或和(单调栈+按位运算)

    首先看到与或,很显然想到按照位拆分运算.然后就变成了0/1矩阵,要使矩阵在当前位与为1,则矩阵全为1,如果是或为1,则是矩阵不全为0,然后求全为0/1的矩阵个数即可.记录c[i][j]表示以a[i][ ...

  3. Matlab高级教程_第二篇:Matlab相见恨晚的模块_02_并行运算-2

    1 MATLAB并行计算-从个人桌面到远程集群和云(陈伟/魏奋)视频摘录笔记 https://cn.mathworks.com/videos/parallel-computing-with-matla ...

  4. windows 环境下Maven私服搭建

    使用Nexus.3.11在Windows环境上搭建1.下载nexus.3.11.zip包https://www.sonatype.com/download-oss-sonatype 下载下来之后,进行 ...

  5. moco jar包下载

    http://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/0.11.0/ 选择moco-runner-0.11.0-standalo ...

  6. PAT甲级——1008 Elevator

    PATA1008 Elevator The highest building in our city has only one elevator. A request list is made up ...

  7. 007.前端开发知识,前端基础CSS(2020-01-28)

    一.布局 一列固定宽度且居中 两列左窄右宽型 通栏平均分布型 1.一列固定宽度且居中布局<body> .top+.banner+.main+.footer 按Tab键,得到下框中代码 &l ...

  8. Prefix and Suffix

    题目描述 Snuke is interested in strings that satisfy the following conditions: The length of the string ...

  9. iOS 版本更新迭代

    开发中我们可能会遇到这样的需求,当AppStore中有新版本迭代更新,在用户点开APP的时候弹框提醒客户去AppStore更新APP.这里面就有个关键点,判断当前APP与AppStore中的版本高低, ...

  10. WAIC | 奇点云携「酷炫AI应用」亮相2019世界人工智能大会

    你是否还在疑惑“人工智能可否改变世界?” 那么,你该有一些危机感了. 机器视觉.自然语言处理.智能语音.机器人问诊.智慧驾驶……这些AI技术及应用早已渗入了我们日常生活的点滴. 29日,以「智联世界, ...