Node.js 是一个异步的世界,官方 API 支持的都是 callback 形式的异步编程模型,这会带来许多问题,例如:1、callback 嵌套问题 2、异步函数中可能同步调用 callback 返回数据,带来不一致性。为了解决以上问题 Koa 出现了。koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的Web 框架。 使用 koa 编写 web 应用,可以免除重复繁琐的回调函数嵌套, 并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件, 它仅仅提供了一个轻量优雅的函数库,使得编写 Web 应用变得得心应手。开发思路和 express 差不多,最大的特点就是可以避免异步嵌套。
英语官网:http://koajs.com
中文官网:http://www.itying.com/koa
Koa2.x 框架的安装使用
1、安装 Node.js 8.x 以上的版本
- 开发 Koa2 之前,Node.js 是有要求的,它要求 Node.js 版本高于 V7.6。因为 node.js 7.6 版本开始完全支持 async/await,所以才能完全你支持我们的 Koa2。
2 安装命令
1
npm install koa --save
简单使用
- epress自带路由 koa需要安装路由模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/引入 Koa
const koa=require('koa');
const app=new koa();
//配置中间件 (可以先当做路由)
app.use(
async (ctx)=>{ ctx.body='hello koa2'}
)
//express写法
app.use(function(req,res){
res.send('返回数据')
})
//监听端口
app.listen(3000);koa router路由
- 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等) 组成的,涉及到应用如何响应客户端对某个网站节点的访问。
- 通俗的讲:路由就是根据不同的 URL 地址,加载不同的页面实现不同的功能。
- Koa 中的路由和 Express 有所不同,在 Express 中直接引入 Express 就可以配置路由,但是在
- Koa 中我们需要安装对应的 koa-router 路由模块来实现。
1
npm install koa-router --save
路由的基本使用
- 官方文档 https://www.npmjs.com/package/koa-router
*路由中的ctx参数 context 包含了request和 response等信息*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const Koa = require('koa');
//注意:引入的方式 引入并且实例化路由
const router = require('koa-router')();
const app = new Koa();
//配置路由 ctx 上下文 context 包含了request和 response等信息
router.get('/', function (ctx, next) {
//返回数据 相当于原声的res.writeHead() res.end()
ctx.body="Hello koa";
})
router.get('/news',(ctx,next)=>{
ctx.body="新闻 page"
})
app.use(router.routes());//作用:启动路由
// 作用:这是官方文档的推荐用法,
//我们可以看到 router.allowedMethods()用在了路由匹配 router.routes()之后,
//所以在当所有路由中间件最后调用.出错会根据 ctx.status 设置 response 响应头
app.use(router.allowedMethods());
app.listen(3000,()=>{
console.log('starting at port 3000');
});- 路由最好带上async
1
2
3router.get('/news',async(ctx,next)=>{
ctx.body="新闻 page"
})koa路由动态 get传值以及获取get传值
- 在 koa2 中 GET 传值通过 request 接收,但是接收的方法有两种:query 和 querystring。
- query:返回的是格式化好的参数对象。
- querystring:返回的是请求字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17http://localhost:3000/newscontent?cid=123&aaa=dss4
router.get('/newscontent',(ctx,next)=>{
//重ctx中读取get传值
//获取的是对象 用的最多的 推荐方式
console.log(ctx.query); //{ cid: '123', aaa: 'dss4' }
console.log(ctx.querystring) //cid=123&aaa=dss4
console.log(ctx.url); //获取url地址
//重ctx里面的request中读取get传值
console.log(ctx.request); //包括域名 url等信息
console.log(ctx.request.url)
console.log(ctx.request.query)
console.log(ctx.request.querystring)
ctx.body('hello koa')
})Koa 动态路由
1
2
3
4
5//http://localhost:3000/newscontent/aaaa
router.get('newscontent', '/newscontent/:aid',async(ctx, next)=>{
//获取动态路由的传值
console.log(ctx.params); //{ aid: 'aaaa' }
}) - 也可以传递多个参数
1
2
3
4
5
6//http://localhost:3000/package/aaaa/bbb
router.get('/package/:aid/:cid',async(ctx, next)=>{
//获取动态路由的传值
console.log(ctx.params); //{ aid: 'aaaa', cid: 'bbb' }
ctx.body="Hello koa";
})Koa 的中间件
什么是 Koa 的中间件
- 通俗的讲:
*中间件就是匹配路由之前或者匹配路由完成做的一系列的操作*
我们就可以把它叫做中间件 - 在express 中间件(Middleware)是一个函数,它可以访问请求对象(request object (req)),响应对象(response object (res)), 和 web 应用中处理请求-响应循环流程中的中间件,一般被命名为 next 的变量。在 Koa 中中间件和 express 有点类似。
- 中间件的功能包括:执行任何代码、修改请求和响应对象、终结请求-响应循环、调用堆栈中的下一个中间件
- 如果我的 get、post 回调函数中,没有 next 参数,那么就匹配上第一个路由,就不会往下匹配了。
*如果想往下匹配的话,那么需要写 next()*
.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
26const Koa = require('koa');
//注意:引入的方式
const router = require('koa-router')();
const app = new Koa();
/*中间件可以设置多个路由 不写是匹配所有路由*/
/*匹配所有路由之前 打印日期*/
app.use(async (ctx,next)=>{
console.log(new Date());
//如果不写这个next 这个路由被匹配到了就不会继续向下匹配
//匹配一个路由后其余的路由会not found
await next()
})
router.get('/',async(ctx, next)=>{
ctx.body="Hello koa";
})
router.get('/newscontent',(ctx,next)=>{
ctx.body="新闻 page"
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3000,()=>{
console.log('starting at port 3000');
});路由级中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const Koa = require('koa');
//注意:引入的方式
const router = require('koa-router')();
const app = new Koa();
// 匹配带news路由后继续向下匹配路由
router.get('/news',async(ctx, next)=>{
console.log('这是一个新闻');
await next()
})
router.get('/news',(ctx)=>{
ctx.body="新闻 page"
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3000,()=>{
console.log('starting at port 3000');
});错误处理中间件
1
2
3
4
5
6
7
8
9//没有的话返回404数据
app.use(async (ctx,next)=> {
console.log('这是一个中间件');
next();
if(ctx.status==404){
ctx.status = 404;
ctx.body="这是一个 404 页面"
}
});Koa中使用ejs模板引擎
- 文档 https://www.npmjs.com/package/koa-views
- 安装 koa-views
1
npm install --save koa-views
- 安装 ejs
1
npm install ejs --save
- 引入 koa-views 配置中间件
1
2
3
4
5const views = require('koa-views');
//模板的后缀名是ejs
app.use(views(__dirname, { extension: 'ejs' }))
//这样配置也可以 注意如果这样配置的话 模板的后缀名是.html
app.use(views('views', { map: {html: 'ejs' }})); - 渲染模板引擎(数据渲染到index.ejs页面,data数据)
1
2
3
4let list=['11111','22222','33333']
await ctx.render('index',()=>{
list:list
});代码示范
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
30
31
32
33
34
35
36
37
38
39var Koa=require('koa');
var router = require('koa-router')();
var views = require('koa-views');
var app=new Koa();
//配置模板引擎中间件 --第三方中间件
//第一个参数是模板的位置 views文件夹
app.use(views('views',{
extension:'ejs' /*应用ejs模板引擎*/
}))
//写一个中间件配置公共的信息 全局信息每个页面都可以用的
app.use(async (ctx,next)=>{
ctx.state.userinfo='张三';
await next();/*继续向下匹配路由*/
})
router.get('/',async (ctx)=>{
let title="你好ejs 这是一个ejs模板引擎";
await ctx.render('index',{
title:title
});
})
router.get('/news',async (ctx)=>{
let list=['11111','22222','33333'];
let content="<h2>这是一个h2</h2>";
let num=12;
await ctx.render('news',{
list:list,
content:content,
num:num
})
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3000,()=>{
console.log('starting at port 3000');
});ejs模板引擎语法
- 有时候一个部分会很多页面都用到 引用公共组件
1
2//header.ejs是公共的头部组件 public是文件夹
<% include public/header.ejs%> - 输出内容
1
<%=num%>
- 在页面上输出html标签
1
<%-content%>
- for循环 if判断写法差不都
1
2
3
4
5
6
7
8
9<% for(var i=0;i<list.length;i++){%>
<li><%=list[i]%></li>
<% } %>
<% if(true){ %>
<div>true</div>
<%} else{ %>
<div>false</div>
<% } %> - koa在中间件定义了全局数据直接在用到的页面上<%=userinfo%>引用即可
koa post 提交数据 推荐使用koa-bodyparser中间件
原声Node获取post数据
- index.ejs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/doAdd" method="post">
用户名: <input type="text" name="username"/>
<br/>
<br/>
密 码: <input type="password" name="password"/>
<br/>
<br/>
<button type="submit">提交</button>
</form>
</body>
</html> - 封装post获取数据 common.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18exports.getPostData=function(ctx){
//获取数据 异步
return new Promise(function(resolve,reject){
try{
let str='';
ctx.req.on('data',function(chunk){
str+=chunk;
})
ctx.req.on('end',function(chunk){
resolve(str)
})
}catch(err){
reject(err)
}
})
} - 调用获取提交数据
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
28var Koa=require('koa');
var router = require('koa-router')();
var views = require('koa-views');
//封装post请求数据
common = require('./module/common.js');
var app=new Koa();
/*应用ejs模板引擎*/
app.use(views('views',{
extension:'ejs'
}))
router.get('/',async (ctx)=>{
await ctx.render('index')
})
router.post('/doAdd',async (ctx)=>{
//原生nodejs 在koa中获取表单提交的数据
var data=await common.getPostData(ctx);
console.log(data);
ctx.body=data;
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3000,()=>{
console.log('starting at port 3000');
});使用koa-bodyparser中间件获取post数据
- Koa中koa-bodyparser中间件获取表单提交的数据
- 1.npm install –save koa-bodyparser
- 2.引入var bodyParser = require(‘koa-bodyparser’);
- 3.app.use(bodyParser());
- 4.ctx.request.body; 获取表单提交的数据
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
27var Koa=require('koa');
var router = require('koa-router')();
var views = require('koa-views');
var bodyParser = require('koa-bodyparser');
var app=new Koa();
/*应用ejs模板引擎*/
app.use(views('views',{
extension:'ejs'
}))
//配置post bodyparser的中间件
app.use(bodyParser());
router.get('/',async (ctx)=>{
await ctx.render('index');
})
//接收post提交的数据
router.post('/doAdd',async (ctx)=>{
console.log(ctx.request.body);
ctx.body=ctx.request.body; //获取表单提交的数据
})
app.use(router.routes()); /*启动路由*/
app.use(router.allowedMethods());
app.listen(3000);静态资源中间件
koa-static
- 1、安装 koa-static
1
npm install --save koa-static
- 2、引入配置中间件
- http://localhost:3000/css/basic.css首先去static目录找 ,如果能找到返回对应的文件,找不到 next()
1
2
3
4
5
6const static = require('koa-static');
//配置静态web服务的中间件
app.use(static('./static'));
app.use(static(__dirname+'/static'));
//koa静态资源中间件可以配置多个
app.use(static(__dirname+'/public')) - 不过在前端引用的静态资源就可以省略static的路径
1
2
3
4正常
<link rel="stylesheet" href="../static/css/basic.css"/>
用中间件以后
<link rel="stylesheet" href="css/basic.css"/> - 个人感觉这种写法很别扭 还有一种写法可以正常引入
koa-static-server
1
2
3
4
5
6
7
8var static = require('koa-static-server');
app.use(static({
rootDir:'./static/',//整个工程目录
rootPath:'/static/',//url地址访问static路径
maxage:0 //指定缓存 0不缓存
}));
// 也可以多个调用 在复制一份即可
正常引入即可<link rel="stylesheet" href="../static/css/basic.css"/>art-template高性能模板引擎的使用
- 官方文档 http://aui.github.io/art-template/koa/
安装art-template
1
2npm install --save art-template
npm install --save koa-art-template - 引入art-template
1
const render = require('koa-art-template');
- 配置模板引擎
1
2
3
4
5
6//配置 koa-art-template模板引擎
render(app, {
root: path.join(__dirname, 'views'), // 视图的位置
extname: '.html', // 后缀名
debug: process.env.NODE_ENV !== 'production' //是否开启调试模式
}); - 渲染数据
1
await ctx.render('user');
- 代码示例
1
2
3
4
5
6
7
8
9
10
11router.get('/news',async (ctx)=>{
let app={
name:'张三11',
h:'<h2>这是一个h211</h2>',
num:20,
data:['11111111','2222222222','33333333333']
};
await ctx.render('news',{
list:app
});
})koa-art-template模板语法
- 支持ejs语法 支持node也支持浏览器
- 语法类似angular
- 参考地址 http://aui.github.io/art-template/zh-cn/docs/syntax.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<body>
<h2>绑定数据</h2>
{{list.name}}
<h2>绑定html数据</h2>
{{@list.h}}
<h2>条件</h2>
{{if num>20}} <sapn>大于20</sapn> {{else}} <sapn>小于20</sapn>{{/if}}
<h2>循环数据</h2>
<ul>
{{each list.data}}
<li>{{$index}}---{{$value}}</li>
{{/each}}
</ul>
<h2>子组件</h2>
{{include 'public/footer.html'}}
</body>Koa Cookie的使用
- 设置cookie
1
2
3ctx.cookies.set('userinfo','zhangsan',{
maxAge:60*1000*60
}); - 获取cookie
1
var userinfo=ctx.cookies.get('userinfo');
- 设置cookie中一些参数 不过默认都是设置好的
1
2
3
4
5
6
7
8
9
10ctx.cookies.set('userinfo','zhangsan2222',{
/*过期时间*/
maxAge:60*1000*60,
/*配置可以访问的页面*/
path:'/news',
/*正常情况不要设置 默认就是当前域下面的所有页面都可以方法*/
domain:'.baidu.com'
//true表示这个cookie只有服务器端可以访问,false表示客户端,(js服务器端都可以访问
httpOnly:false,
}); - 注意设置中文cookie会报错 需要转换
1
2
3
4var userinfo=new Buffer('张三').toString('base64');
ctx.cookies.set('userinfo',userinfo,{
maxAge:60*1000*60
}); - 获取cookie
1
2var data=ctx.cookies.get('userinfo');
var userinfo=new Buffer(data, 'base64').toString(); - 汉字转换base64和base64转换为汉字
1
2
3
4console.log(new Buffer('张三').toString('base64'));// 转换成 base64 字符
//5byg5LiJ
console.log(new Buffer('5byg5LiJ', 'base64').toString());// 还原 base
//张三Koa Session 的使用
- 文档 https://www.npmjs.com/package/koa-session
Session 简单介绍
- session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而session 保存在服务器上。
Session 的工作流程
- 当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session 对象,生成一个类似于key,value 的键值对, 然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带 key(cookie),找到对应的 session(value)。 客户的信息都保存在session 中
koa-session 的使用
- 1.安装 koa-session
1
npm install koa-session --save
- 2.引入koa-session
1
2
3const session = require('koa-session');
const Koa = require('koa');
const app = new Koa(); - 3.设置官方文档提供的中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23app.keys = ['some secret hurr']; /*cookie的签名不用管扔着就行*/
const CONFIG = {
key: 'koa:sess', /** 默认 */
/* cookie的过期时间 【需要修改】 */
maxAge: 10000,
/** (boolean) can overwrite or not (default true) 没有效果,默认 */
overwrite: true,
/* true表示只有服务器端可以获取cookie */
httpOnly: true,
/* 默认 签名 */
signed: true,
/* 在每次请求时强行设置cookie,这将重置cookie过期时间(默认false)【需要修改】 */
rolling: true,
/*半小时过期 用户写文章但是写了两个小时 所以在用户触发的时候重新设置过期时间 */
renew: false, /* 会话几乎过期时更新会话 【需要修改】*/
};
app.use(session(CONFIG, app));使用koa-session
1
2设置值 ctx.session.username = "张三";
获取值 ctx.session.usernameCookie 和 Session 区别
- 1、cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
- 2、cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗考虑到安全应当使用 session。
- 3、session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用 COOKIE。
- 4、单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。
Koa操作MongoDb数据库的DB类库
- 基于官方的 node-mongodb-native 驱动,封装一个更小、更快、更灵活的 DB 模块, 让我们用 nodejs 操作 Mongodb 数据库更方便、更灵活。