学习nodejs 中的koa2
一. 什么是koa
类似于 express , koa是一个基于nodejs的服务端框架
二. koa的简单使用
初始化项目
1
npm init
安装koa
1
npm install koa --save
在app.js中(自定义项目启动的入口文件)
实例化koa
1
2const Koa = require('koa');
const app = new Koa();设置监听访问页面路径的中间件(koa中一切皆是中间件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 为了方便监听, 需要从koa中引入路由中间件
const Router = require('koa-router');
const router = Router()
// 设置全局中间件
app.use(async(ctx, next) => {
console.log('I am the first middleware')
await next()
console.log('first middleware end calling')
})
app.use(async (ctx, next) => {
console.log('I am the second middleware')
await next()
console.log('second middleware end calling')
})
// 定义路由
router.get('/api/test1', async(ctx, next) => {
console.log('I am the router middleware => /api/test1')
ctx.body = 'hello'
})
router.get('/api/testerror', async(ctx, next) => {
throw new Error('I am error.')
})
// 设置路由中间件
app.use(router.routes())设置服务器启动端口
1
2
3
4
5
6
7
8// 注意, 在nodejs 大多数操作都是异步的, 因此以下代码有可能服务器没有启动就已经输出这句话了
app.listen(3000)
console.log('server listening at port 3000');
// 保险的做法, 我认为应该是
app.listen(3000, ()=> {
console.log('server listening at port 3000')
})在 koa中 ctx (上下文) , 在初次学习中, 可以简单看成 express框架中的req和res的集合
三. 中间件(middleware)
3.1 什么是中间件
*通俗来讲, * 中间件就是匹配路由之前或者匹配路由之后所完成的一系列操作就是中间件
3.2 中间件功能
- 执行任何代码
- 修改请求和响应对象
- 终结请求-响应循环
- 调用堆栈中的下一个中间件(next)
3.3 中间件分类
- 应用级中间件 (koa)
- 路由级中间件 (koa-router)
- 错误处理中间件 ( 可以在应用级中间件中 使用ctx.status===404 , 进行全局错误处理 )
- 第三方中间件: 如用于处理post传值的中间件\静态托管的static
3.4 路由中间件多次匹配
多个中间件可以对同一路由进行多次匹配
1 | router.get("/err", async (ctx, next) => { |
上述代码在访问 http://localhost:3000/err, 会在后端控制台输出 “this is error page”, 会在前端页面中输出 “this is error page”
3.5 中间件优先级
与express框架有点不同, 在express中, 中间件的优先级往往取决于写法的先后, 写在前面的往往比写在后面的优先匹配 ( 代码从上往下读 )
但是在koa中, 中间件的先后是符合一定规则的,执行流程类似于洋葱图
四. EJS模板引擎
4.1 ejs 模板引擎的安装
安装 koa-views和ejs
1
npm install --save koa-views / cnpm install --save koa-views
引入koa-views配置中间件
1
2
3
4
5
6
7
8
9
10
11
12const views = require("koa-views");
// 注意, 这只是渲染的其中一种方法, 而且这样子设置之后, render函数只能识别 html的后缀名文件
app.use(views("views", {map: {html: "ejs"}}));
// 还有一种设置方法, 推荐这种写法, 这种写法可以识别ejs的文件后缀名, 并且名字明确了模板文件的根路径
// views字符串是指模板文件夹的根路径, 当前设置是指, 将当前项目根目录中的Views文件夹(没有则需要手动创建) 设置成模板文件夹根目录
app.use(views("views", {
extension: "ejs"
}))
// 或者这种写法
app.use(views(__dirname, {extension: "ejs"}))
4.2 EJS模板的使用
4.2.1 使用变量
在koa的路由中设置需要传入EJS的变量
1 | router.get("/me", async (ctx, next) => { |
在EJS中调用
1 | <h5><%= title%></h5> |
4.2.2 数组的循环渲染
在ejs中传入需要循环的数组
1 | router.get("/me", async (ctx, next) => { |
在ejs 在EJS中使用
1 | <%# 第一种循环方式 %> |
在ejs中 当前版本好像只支持 for 循环
4.2.3 条件渲染
这个可以参照官方文档进行操作, 没有什么需要特别提出的
4.2.4 模板引用
在VIews文件夹定义一个layout文件夹, 在layout中有一个header.ejs
1 | <h1 class="header"> |
在index.ejs中引用 header.ejs内容
1 | <% include layout/header.ejs %> |
注意!!!
可能每个版本的ejs 引入都有可能有或多或少的问题, 当发现上述方法引入出现语法报错时, 可以尝试的使用以下语法引入
1 | <% include("layout/header.ejs") %> |
4.2.5 模板引用传值
在引用的过程中, 传入即可, 在调用header.ejs模板时传入一个 name = wang的值
在index.ejs中
1 | <% include("layout/header.ejs", {name: "wang"}) %> |
在header.ejs中
1 | <h3 class="name"> |
4.3 session作用域
如果我们想在每一个router中都使用同一组数据, 则可以将该数据置入session中, 然后在ejs中直接调用
而且这种场景一般都需要使用中间件来配置相关的信息
在中间件配置信息
1 | // 设置全局session中间件 |
在session.ejs模板中直接使用
1 | <h2 class="name"> |
五. 获取post提交数据
5.1 原生NodeJS获取post提交数据
首先先定义获取post传值的方法
在项目跟目录下定义一个 common.js , 内容如下
1 | exports.getPostData = function (ctx) { |
在 router中建立监听form表单的提交
1 | const common = require('./common'); |
5.2 koa-bodyparse获取提交post提交数据
5.2.1 安装 koa-bodyparse
1 | npm install koa-bodyparse --save |
5.2.2 引入配置中间件
1 | const Koa = require("koa"); |
5.2.3 使用中间件
1 | app.use(async (ctx, next) => { |
六. 静态资源托管
在模型中, 如果想引入静态资源, 则需要引入静态资源托管的中间件, 对文件路径进行重新适配, 在koa中使用的是 koa-static中间件进行托管, 详情可直接了解官方文档: https://www.npmjs.com/package/koa-static
6.1 koa-static 的安装
1 | npm install koa-static --save |
6.2 配置中间
1 | const Koa = require('koa'); |
七. koa-cookies
cookies是存储在用户浏览器中的一个变量, 可以让我们用同一个浏览器访问同一个域名的时候共享数据
(注意是同一个域名的时候)
HTTP是无状态协议, 当你浏览了一个页面, 然后转到同一个网站的其他页面时候, 服务器无法认识到是同一个浏览器在访问同一个网站, 每次访问都与上一次访问没有任何关系
关于koa-cookies的更多使用功能可以详见官方文档, 这里只是讲解简单用法
官方文档: https://www.npmjs.com/package/koa-cookies
7.1 koa-cookies的安装
1 | npm i koa-cookies --save |
7.2 koa-cookies使用
1 | // const { clearCookie, setCookie } = require('koa-cookies'); |
7.3 配置中间件
1 | app.use(setCookie('foo', 'bar', config)) |
7.4 koa-cookies 的配置信息
1 | setCookieConfig = { |
7.5 在koa中配置中文cookies
*思路: *可以将中文转成 buffer 64位编码, 进行保存, 在取值的时候, 再将 64位编码转成字符串
第一步, 将中文转换成64位编码
1
2
3// 注意!!! 在最新版本中, 直接调用 Buffer可能会存在问题, 官方建议使用别的方法
// Buffer() is deprecated due to security and usability issues.
const name = new Buffer("张三").toString("base64");// 输出 5byg5LiJ第二步, 将64位编码转成字符串
1
const name = new Buffer("5byg5LiJ", "base64").toSting(); // 输出张三
八. koa与MongoDB
8.1 MongoDB封装
pass
详情了解官方文档: https://docs.mongodb.com/drivers/node/
番外
一. commonJs
1.1 什么是commonJS
只用一句话就可以简单表述出来
CommonJs 就是模块化的标准, NodeJs就是CommonJs的实现
Node应用是由模块组成的, 采用CommonJs模块规范
1.2 CommonJs模块分类
模块又分为两大类:
- 系统模块: 即 NodeJs的内置模块, 无需安装即可使用, 如: path,os, fs等模块
- 文件模块: 由用户编写的第三方文件模块, 使用时需要安装, 如:axios, cheerio, puppeteer等模块
1.3 CommonJs模块规范
我们可以把公共的功能抽离成一个单独的js文件, 即一个模块, 在默认的情况下这个模块里面的属性以及方法, 外界都无法访问, 要想暴露出去, 就需要通过export 或者 module.exports暴露属性或者方法
1
2
3
4
5
6
7
8
9
10// api.js
const axios = {
get() {
console.log("调用get方法")
},
post() {
console.log("调用post方法")
}
}
export.axios = axios
在需要使用这些文件的模块中, 通过require方法, 引入这些模块
1
2
3// index.js
const axios = require("api");
axios.get();
注意, 在一个叫node_modules 文件夹里面定义的模块, 引入时不需要写完整的路径, 只需要写相对于node_modules文件夹的路径即可
二. art-template模板引擎
适用于koa的模板引擎或者说适用于nodeJS的模板引擎有很多, 比如 jade, ejs, nunjucks(thinkjs默认引擎), art-template
art-template是一个简约, 超快的模板引擎, 它采用作用域声明的技术来优化模板渲染速度, 从而获得接近JS极限的运行速度, 总得来说是挺有意思的一款模板引擎, 之所以不放在正篇说, 是个人认为模板引擎只需掌握一种即可, 了解其渲染原理, 不必过多掌握多种模板引擎
*值得注意的是: *art-template支持ejs 的语法, 也可以用自己类似于angular数据绑定的写法
2. 1 art-template安装
1 | # koa 的模板引擎需要依赖 koa-views的支持 |
2.2 art-template 配置
1 | const path = require("path"); |
2.2 art-template使用
具体详见官方文档, 语法跟ejs 差不多, 同时也支持类似于 angular的语法
2.2.1 报错提示
在开启debug模式之后, art-template语法错误之后会提示报错位置
1 | <!-- |
三. 对象冒充结合原型链实现继承(ES5)
传统继承模式
1 | function Person (name, age){ |
冒充对象结合原型链实现继承
1 | function Person(name,age,hobby){ |
四. 单例模式
4.1 ES5 的单例实现
1 | function A(name){ |
4.2 ES6 的单例实现
1 | // 通过ES6实现单例, 更较为常用 |