目录
1.课堂目标及知识点
2.koa介绍
3.koa使用
3.1koa安装
3.2一个简单的koa服务器
3.3Koa 利用中间件 控制"上游",调用"下游“;
4.Application对象
5.上下文context对象常用属性及方法
5.1context 将node中的request和response 封装到一个对象中,并提供一些新的api提供给用户进行操作;
5.2request及response别名
5.2.1koa会把ctx.request上的属性直接挂载到ctx上如:
5.2.2同样也会把ctx.response上的属性直接挂载到ctx上如:
5.2.3ctx.status 获取响应状态。
5.2.4http状态码
6.koa常用中间件——koa-router路由
6.1koa-router安装
6.2Koa-router使用
6.3Koa-router推荐使用RESTful架构API。
7.koa常用中间件——koa-views加载页面
7.1安装 koa-views
7.2使用koa-views
8.koa常用中间件——koa-static
9.使用koa框架重构新闻列表页面
1.课堂目标及知识点
课堂目标
- npm包管理器使用
- koa使用
- 了解koa中的applition对象及context对象
- koa-views使用
- koa-static使用
- 使用koa-router中间件搭建路由
- 了解常见http状态码
本节知识点
- http模块实现模板加载及静态文件处理
- koa的安装及使用
- Application及context对象介绍
- 常用http状态码介绍
- 路由中间件koa-router介绍
- 中间件koa-views介绍
2.koa介绍
- koa是express原班人马打造的轻量级、健壮性、富有表现力的nodejs的框架。
- 目前koa有koa1和koa2两个版本;
- koa2依赖Node.js 7.6.0或者更高版本;
- koa不在内核方法中绑定任何中间件,它仅仅是一个轻量级的函数库,几乎所有功能都必须通过第三方插件来实现。
3.koa使用
3.1koa安装
$ npm i koa
3.2一个简单的koa服务器
const Koa = require('koa');
const app = new Koa();
?
app.use(async ctx => {ctx.body = 'Hello World';
});
?
app.listen(3000);
3.3Koa 利用中间件 控制"上游",调用"下游“;
- koa是包含一组中间件函数的对象;可以将app.use里的函数理解成中间件
- ctx即context上下文,是原来node.js的req和res的合体分别对应ctx.req、ctx.res,context会将res和req封装成ctx.request和ctx.respones;
//这里的middleWare函数就是一个中间件
let middleWare = async (ctx,next)=>{console.log("first middleWare");ctx.body = "hello world";
}
app.use(middleWare);
- 通过next()将控制转交给另一个中间件;有next()函数才会执行下一个中间件。next()调用后才会执行中间件,不调用则不会执行
- 一般都是使用第三方提供的中间件。
- 中间件中如果有异步逻辑,通过async await处理(await后跟的一定是promise对象);async await同步写法实现异步功能
- 上述过程也可以通过"洋葱模型“来解释中间件执行顺序
中间件执行示例:有next()函数才会执行下一个中间件。如此处next()调用后才会执行中间件,不调用则不会执行
//node.js的框架koa
const Koa = require("koa");
const app = new Koa();const middleWare3 = require("./m3");//中间件
let middleWare1 = (cxt, next) => {console.log("one start......");cxt.body = "hello world11111";//当前表示中间件转交给下一个中间件,有next()函数才会执行下一个中间件。如此处next()调用后才会执行中间件,不调用则不会执行next();console.log("one end......");
}let middleWare2 = (cxt, next) => {console.log("two start......");cxt.body = "hello world22222";next();console.log("two end......");
}app.use(middleWare1);
app.use(middleWare2);
// 中间件也可以是引入方式
app.use(middleWare3);
/*中间件执行结果:one start......two start......three start........three end ..........two end......one end......*/// app.on("error",(err)=>{
// console.log(err);
// });
app.listen(4000);
中间件执行结果:
one start......
two start......
three start........
three end ..........
two end......
one end......
4.Application对象
- application是koa的实例 简写app
- app.use 将给定的中间件方法添加到此应用程序,分为同步和异步,异步:通过es7中的async和await来处理
- app.listen设置服务器端口;
- app.on 错误处理;
5.上下文context对象常用属性及方法
5.1context 将node中的request和response 封装到一个对象中,并提供一些新的api提供给用户进行操作;
- ctx.app:应用程序实例引用,等同于app;
- ctx.req:Node 的
request
对象. - ctx.res:Node 的
response
对象. - ctx.request:koa中的Request对象;
- ctx.response:koa中的response对象;
- ctx.state:对象命名空间,通过中间件传递信息;
- ctx.throw:抛出错误;
错误处理:
// 错误处理app.on("error",(err)=>{console.log(err);});
5.2request及response别名
5.2.1koa会把ctx.request上的属性直接挂载到ctx上如:
ctx.header
//头信息;ctx.headers
ctx.method
ctx.method=
ctx.request.methodctx.url
ctx.url=ctx
.request.url
5.2.2同样也会把ctx.response上的属性直接挂载到ctx上如:
ctx.body
ctx.body=ctx.response.body
ctx.status
ctx.status=ctx.response.status
5.2.3ctx.status 获取响应状态。
默认情况下,response.status
设置为 404
而不是像 node 的 res.statusCode
那样默认为 200
。
原生js和原生node.js中可以通过ctx.setHeader和ctx.writeHead()进行设置
5.2.4http状态码
-
http状态码:1xx(消息)、2xx(成功)、3xx(重定向)、4xx(请求错误)、5xx和6xx(服务器错误)
-
常见http状态码 (302 location 跳转)
HTTP状态码 描述 100 继续。继续响应剩余部分,进行提交请求 200 成功 301 永久移动。请求资源永久移动到新位置 302 临时移动。请求资源零时移动到新位置 304 未修改。请求资源对比上次未被修改,响应中不包含资源内容 401 未授权,需要身份验证 403 禁止。请求被拒绝 404 未找到,服务器未找到需要资源 500 服务器内部错误。服务器遇到错误,无法完成请求 503 服务器不可用。零时服务过载,无法处理请求 - 设置状态码
一般在获取成功或失败数据。如{info:"请求成功",status:0}以外,还需要给浏览器给出状态码,才更符合浏览器的规则
router.get("/getData", async (cxt,next)=>{//cxt.status设置状态码//302临时跳转,会跳转到设置的地址cxt.status = 302;// 设置头部cxt.set("location","http://www.baidu.com");cxt.body = {name:'lmf',age:23};
});
6.koa常用中间件——koa-router路由
-
路由是引导匹配之意,是匹配url到相应处理程序的活动。
6.1koa-router安装
npm i koa-router -S
6.2Koa-router使用
- 请求方式:get/post/put/delete等;
- 使用localhost:5000和localhost:5000/地址是一样的
- koa框架中cxt.body会将对象数据直接转换为json数据格式
- 使用app.use(router.routes());将app(koa框架)和router进行关联
- koa-router中加载文件必须使用异步才能加载到文件,async await时同步写法实现异步功能,await后必须返回的是promise对象,此处await后,cxt.render()底层有返回promise对象
//中间件koa-router
const Koa = require("koa");
const Router = require("koa-router");let app = new Koa();
let router = new Router();//请求方式:get / post /put /delete 等
//直接打印"/"和什么都不输入一样
router.get("/",async (cxt,next)=>{cxt.body = "hello world";
});//传输对象格式数据(cxt.body会将对象数据直接转换为json数据)
//{"name":"lmf","age":23}
router.get("/getData", async (cxt,next)=>{//cxt.status设置状态码//302临时跳转,会跳转到设置的地址cxt.status = 302;cxt.set("location","http://www.baidu.com");// koa会直接将对象转为jsoncxt.body = {name:'lmf',age:23};
});// 通过此句将app和router进行关联
app.use(router.routes());
app.listen("5000");
6.3Koa-router推荐使用RESTful架构API。
Restful的全称是Representational State Transfer 即表现层转移。
- RESTful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。基于这个风格设计可以更简洁,更有层次;
- 非RESTful架构api:
- 使用RESTful架构设计api
REST设计一般符合如下条件:
- 程序或者应用的事物都应该被抽象为资源
- 每个资源对应唯一的URI(uri是统一资源标识符)
- 使用统一接口对资源进行操作
- 对资源的各种操作不会改变资源标识
- 所有操作都是无状态的(如session等)
一般的请求接口:
- www.test.com:/90/addUser 增加
- www.test.com:/90/deleteUser 删除
- www.test.com:/90/updateUser 修改
- www.test.com:/90/getUser 获取
REST设计的请求接口:接口地址都一样,而是通过请求方式的不同跳转到不同的方法。
- www.test.com:/90/user 增加 post
- www.test.com:/90/user 删除 delele
- www.test.com:/90/user 修改 put
- www.test.com:/90/user 获取 get
好处:
- 这种方式更符合浏览器规则;
- 在做多终端(PC端,安卓,ios等)时请求都可以通用;
- 接口抽象出来;
- 有统一的标识符
- 无状态原则,session等会话状态是不会保存的。所以这些就只能通过前端通过cookie进行保存,或者现有的解决方法jwt(json web token)
7.koa常用中间件——koa-views加载页面
- koa-views用于加载模板文件;
- 可以是任何类型的文件:html,也可以是模块文件(pug或nunjucks)
- 使用pug模板文件时,必须加载文件后缀名。如index.pug。
- nunjucks使用时不使用koa-views模块而是使用koa-nunjucks-2模块
7.1安装 koa-views
npm i koa-views -S
7.2使用koa-views
koaviews.js:
注意:可以是任何类型的文件:html,也可以是模块文件(pug或nunjucks),nunjucks使用时不使用koa-views模块而是使用koa-nunjucks-2模块
koa-router中加载文件必须使用异步才能加载到文件,async await同步写法实现异步功能,await后必须返回的是promise对象,此处await后,cxt.render()底层有返回promise对象。
//koa-view 渲染页面的中间件
const Koa = require("koa");
const Router = require("koa-router");
// 注意是koa-views不是koa-view
const views = require("koa-views");let router = new Router();
let app = new Koa();//koa-views设置文件路径和文件类型(路径views一定要和项目中页面文件路径一致)
app.use(views(__dirname+"/views"),{//可以是任何类型的文件:html,也可以是模块文件(pug或nunjucks),nunjucks使用时不使用koa-views模块而是使用koa-nunjucks-2模块map:{html:"pug"}
});//koa-router中加载文件必须使用异步才能加载到文件,async await同步写法实现异步功能,await后必须返回的是promise对象,此处await后,cxt.render()底层有返回promise对象
router.get("/",async (cxt,next)=>{// 注意使用pug时,一定要有pug后缀await cxt.render("index.pug");
});app.use(router.routes());
app.listen(8989);
index.pug:
<!DOCTYPE html>
html(lang="en")headmeta(charset="UTF-8")meta(name="viewport", content="width=device-width, initial-scale=1.0")title Documentbodyh1 pug页面
8.koa常用中间件——koa-static
-
koa-static 是用于加载静态资源的中间件,通过它可以加载css、js等静态资源;
-
安装 koa-static
npm i koa-static
-
使用koa-static
//koa-static 加载静态文件
const Koa = require("koa");
const Router = require("koa-router");
const views = require("koa-views");
const static = require("koa-static");let router = new Router();
let app = new Koa();//koa-view设置设置文件路径和文件类型
app.use(views(__dirname+"/views"),{map:{html:'pug'}
});//koa-static加载静态文件(注意static不需要再写)
app.use(static(__dirname+"/static"));//koa-router中加载文件(必须使用异步才能加载到文件)
router.get("/",async (cxt,next)=>{await cxt.render("index.pug");
});app.use(router.routes());
app.listen("7000");
index.css:
h1 {color:red;
}
index.pug:
<!DOCTYPE html>
html(lang="en")headmeta(charset="UTF-8")meta(name="viewport", content="width=device-width, initial-scale=1.0")title Documentlink(rel="stylesheet", href="/css/index.css")bodyh1 pug页面
9.使用koa框架重构新闻列表页面
注意点:
- 使用static后,在页面再引入静态页面,css,js,img等时路劲就不需要再写到static级;
- 使用cxt.render时,必须使用async await异步加载页面;
- 在node.js版本5.1之前通过命令:npm i 模块名 -S时,会自动创建package.json文件,但5.1之后只会自动创建package-lock.json文件(这个文件比package.json文件中的描述内容更加详尽),所以每次创建项目后,必须手动通过npm i在项目路径下创建package.json文件。创建之后,再通过命令 npm i 模块名 -S 安装某个模块时,才会将描述信息覆盖到package.json文件中。且-S会自动写入dependencies ,-D会自动写入devDependencies。另外使用cnpm命令创建模块时只会自动创建package.json文件,不会创建package-lock.json文件,但是不推荐使用cnpm命令。
koa框架重构新闻列表页面完整示例:
index.js:注意需要路由页面时,需要将所有页面需要的数据推送过去
const Koa = require("koa");
const Router = require("koa-router");
const views = require("koa-views");//注意是koa-views
const static = require("koa-static");
const url = require("url");
//注意要使用pug,必须导入pug
const pug = require("pug");//cheerio实现类JQuery功能
const cheerio = require("cheerio");let data = require("./data/data.json");let app = new Koa();
let router = new Router();//可以再views时设置,对应的页面后缀(注意此处设置模板也是views方法的参数)
app.use(views(__dirname + "/views", {map: {html: 'pug'}
}));
// 使用static后,在页面再引入静态页面,css,js,img等时路劲就不需要再写到static级
app.use(static(__dirname + "/static/css"));
app.use(static(__dirname + "/static/img"));//新闻列表显示
//注意使用cxt.render时,必须使用async await异步加载页面
router.get("/news/index", async (cxt, next) => {//分页let pageNum = url.parse(cxt.url,true).query.p || 1;//通过pageNum进行分页let pageSize = 5;let pageTotal = Math.ceil(data.length / pageSize);// 0-4 5-10 ((pageNum-1)*pageSize,pageNum*pageSize)let curData = data.slice((pageNum-1)*pageSize,pageNum*pageSize);//render是方法,不是属性,且文件必须写后缀await cxt.render("viewlist.pug", {curData,pageTotal,pageNum});
});//新闻详细也显示
router.get("/news/detail", async (cxt, next) => {//分页let id = url.parse(cxt.url,true).query.id || 1;let detailData = data.find(item=>id == item.id);//render是方法,不是属性,且文件必须写后缀await cxt.render("detail.pug", {detailData});
});app.use(router.routes());app.listen("8989");
viewlist.pug:
meta(charset='UTF-8')
meta(name='viewport', content='width=device-width,initial-scale=1')
meta(http-equiv='X-UA-Compatible', content='ie=edge')
link(rel='stylesheet', href='../index.css')
title 文章信息展示
.wrapul.news-listeach item in curDatali.newsa(href='javascript:;')img(src='../img.png', alt)divh3a(href='/news/detail?id='+item.id) #{item.title}.infospan.tipsspan #{item.publisher}// <span class="line"></span> span.time | #{item.time}
.pagination- let p = parseInt(pageNum);a.prev(href=`/news/index?p=${Math.max(1,p-1)}`) ?- for(let i=1;i<=pageTotal;i++)- if(p == i)a(href='/news/index?p='+i class="active") #{i}- elsea(href='/news/index?p='+i) #{i}a.next(href=`/news/index?p=${Math.min(pageTotal,p+1)}`) ?
detail.pug:
meta(charset='UTF-8')
meta(name='viewport', content='width=device-width,initial-scale=1')
meta(http-equiv='X-UA-Compatible', content='ie=edge')
title Document
style..text{width: 640px;margin: 0 auto;}.article-info{color:#999;font-size: 14px;}p{font-size: 16px;line-height: 30px;}.texth1.title #{detailData.title}.article-info 类型:#{detailData.publisher} 时间:#{detailData.title}p.content.#{detailData.title}
data.json:数据作相应更改
[{"id": 1,"title": "13岁少年成暴徒,这才是社会的灾难","publisher": "海外网","time": "今天 17:08"},{"id": 2,"title": "举行新闻发布会(全文实录)","publisher": "中国网","time": "今天 16:59"},{"id": 3,"title": "XX学校禁读《哈利·波特》 称咒语召唤邪灵","publisher": "澎湃新闻","time": "今天 16:56"},{"id": 4,"title": "XXXXXXX滚回去","publisher": "海外网","time": "今天 16:54"},{"id": 5,"title": "西XX职位空缺190天后,迎来XX王浩","publisher": "上游新闻","time": "今天 16:54"},{"id": 6,"title": "中国游客在日本突然昏迷 2名韩国消防员及时相救","publisher": "海外网","time": "今天 16:53"},{"id": 7,"title": "XX零售雪上加霜 奢侈品牌普拉达将关闭在XX最大门店","publisher": "观察者网","time": "今天 16:46"},{"id": 8,"title": "拖了18年,XX为何此时从XXX?","publisher": "海外网","time": "今天 16:41"},{"id": 9,"title": "XXXXX?XXXX:系误读","publisher": "环球网","time": "今天 16:37"},{"id": 10,"title": "被男议员骂“不生孩子没尽国家责任” 韩国55岁女学者懵了","publisher": "海外网","time": "今天 16:29"},{"id": 11,"title": "中国XXXXX被提起公诉","publisher": "XXX察院","time": "今天 16:29"},{"id": 12,"title": "XXX假装尿急翻墙逃出营区 10天后在网吧被抓","publisher": "海外网","time": "今天 16:22"},{"id": 13,"title": "XXX“罢课演讲”出糗:成语连说了3遍都没对","publisher": "海外网","time": "今天 16:21"},{"id": 14,"title": "XXX、西安市XXX","publisher": "澎湃新闻网","time": "今天 16:09"},{"id": 15,"title": "XXX:少数暴徒目的在于搞乱XX 进而XXXX","publisher": "新京报网","time": "今天 16:00"},{"id": 16,"title": "XXXXX","publisher": "新京报即时新闻","time": "今天 15:53"},{"id": 17,"title": "XX“双普选”:必须符合XX政治地位","publisher": "新京报即时新闻","time": "今天 15:46"},{"id": 18,"title": "XX是否认为现在XX局势适用紧急法?XXX回应","publisher": "中国网","time": "今天 15:41"},{"id": 19,"title": "XX是否对XX事态设最后期限?XX回应","publisher": "新京报即时新闻","time": "今天 15:35"},{"id": 20,"title": "XX发言人:已到维护“XXX”底线的重要关头","publisher": "新京报即时新闻","time": "今天 15:18"},{"id": 21,"title": "商务部:上周猪肉批发价格上涨8.9%","publisher": "新京报即时新闻","time": "今天 15:14"},{"id": 22,"title": "XXX出糗:这个成语连说三遍都没对","publisher": "海外网","time": "今天 14:54"},{"id": 23,"title": "两高:高考等4类考试组织作弊属犯罪 最高判7年","publisher": "新京报即时新闻","time": "今天 14:33"}
]
index.css:
body {margin: 0;
}ul {margin: 0;padding: 0;list-style: none;
}a {text-decoration: none;color: #404040;
}
.wrap{width: 600px;margin: 0 auto;
}.news-list {width: 600px;
}.news {width: 100%;display: flex;justify-content: space-between;padding: 15px 0;border-bottom: 1px solid #999;
}.info {display: flex;width: 170px;justify-content: space-between;font-size: 12px;color: #888;
}.tips {display: flex;width: 100px;justify-content: space-between;
}.news-list li:nth-child(5) {border-bottom: none;
}
.pagination{display: flex;width: 210px;text-align: center;background-color: rgb(252, 238, 238);border-radius: 25px;overflow: hidden;margin: 0 auto;justify-content: center;
}
.pagination a{width: 30px;line-height: 30px;color: #404040;
}
.pagination a:nth-child(1) {transform: rotate(-45deg) ;
}
.next {transform: rotate(45deg) ;
}
.pagination a:hover{color: rgb(247, 73, 73);
}
.news div{width:420px;
}
.pagination .active {color: rgb(247, 73, 73);
}