Whittney He

清风自来,浅笑安然

  • 主页
所有文章 友链 关于我

Whittney He

清风自来,浅笑安然

  • 主页

koa学习笔记

2018-08-27

前言

Koa 是一个新的、基于Node.js平台的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。

一、基本用法

Koa 必须使用 7.6 以上的Node版本。如果你的版本低于这个要求,就要先升级 Node;

如何查看node版本:

打开运行(快捷键:win+R),然后输入cmd打开命令行工具,在命令行里输入:node -v

1.如何安装koa?

进入之后,我们初始化生产package.json 文件

1
npm init -y

生成package.json后,安装koa包

1
npm n install --save koa

2.简单demo

1
2
3
4
5
6
const Koa = require('koa');
const app = new Koa();
app.use(async(ctx) => {
ctx.body= 'hello world';
})
app.listen(3000);

3.如何运行?

使用node命令,后面加上你想要运行的js的名称(假设js的名字为index)。

1
$ node index.js

访问3000端口

1
访问 http://127.0.0.1:3000

4.什么是async和await?

async

async是异步的简写,表示声明一个异步方法。

使用 async function 可以定义一个 异步函数, 语法为:

1
async function name([param[, param[, ... param]]]) { statements }1

async 函数的返回值很特殊: 不管在函数体内 return 了什么值, async 函数的实际返回值总是一个 Promise 对象. 详细讲就是:

若在 async 函数中 return 了一个值 x, 不管 x 值是什么类型, async 函数的实际返回值总是 Promise.resolve(x).

那么 Promise.resolve(x) 最终返回一个什么样的promise呢? 来看一下MDN的介绍:

Promise.resolve(value)方法返回一个以给定值解析后的Promise对象。但如果这个值是个thenable(即带有then方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态(指resolved/rejected/pending/settled);否则以该值为成功状态返回promise对象。

参考链接:https://blog.csdn.net/juhaotian/article/details/78934097

await

await可以堪称async wait的简写。await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。await 在等待 Promise 对象时会导致 async function 暂停执行, 一直到 Promise 对象决议之后才会 async function 继续执行.

注意:await必须在async方法中才可以使用因为await访问本身就会造成程序停止堵塞,所以必须在异步方法中才可以使用。

1
2
3
4
5
async function testAsync() {
return 'hello async'
}
const result = testAsync();
console.log(result);

结果返回的是Promise。

1
Promise {'hello async'}

5.Get请求的接收

获得GET请求的方式有两种,一种是从request中获得,一种是一直从上下文ctx中获得。

1.通过request接收

在koa2中GET请求通过request接收,但是接受的方法有两种:query和querystring。

通过下面的例子来说明它们两个的区别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Koa = require("koa");
const app = new Koa();
app.use(async(ctx)=>{
let url = ctx.url;
let request = ctx.request;
let req_query = request.query;
let req_querystring = request.querystring;

ctx.body={
url,
req_query,
req_querystring
}
});
app.listen(3000,() => {
console.log("server is starting at port 3000");
});

在http://127.0.0.1:3000 中的显示结果为:

1
2
3
4
5
{
"url": "/",
"req_query": {},
"req_querystring": ""
}

如果在http://127.0.0.1:3000 后面加上一些数据,如 http://127.0.0.1:3000?name=whitttney&age=24

显示的结果为:

1
2
3
4
5
6
7
8
{
"url": "/?name=whittney&age=24",
"req_query": {
"name": "whittney",
"age": "24"
},
"req_querystring": "name=whittney&age=24"
}

由上面结果可以看出query和querystring区别:

1
2
query:返回的是格式化好的参数对象。
querystring:返回的是请求字符串。

2.直接从ctx中获取Get请求

除了在ctx.request中获取Get请求外,还可以直接在ctx中得到GET请求。ctx中也分为query和querystring。

简单demo如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const Koa = require("koa");
const app = new Koa();
app.use(async(ctx)=>{
let url = ctx.url;
let ctx_query = ctx.query;
let ctx_querystring = ctx.querystring;
ctx.body={
url,
ctx_query,
ctx_querystring
}

});
app.listen(3000,() => {
console.log("server is starting at port 3000");
});

在 http://127.0.0.1:3000?name=whitttney&age=24显示结果为:

1
2
3
4
5
6
7
8
{
"url": "/?name=whittney&age=24",
"ctx_query": {
"name": "whittney",
"age": "24"
},
"ctx_querystring": "name=whittney&age=24"
}

6.post请求的接收

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
const Koa = require("koa");
const app = new Koa();
//中间件 koa-bodyparser
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
app.use(async(ctx) => {
if(ctx.url === '/' && ctx.method === 'GET'){
let html = '' +
'<form method="post" action="/">' +
'<p>username</p>'+
'<input name="username"><br/>'+
'<p>age</p>'+
'<input name="age"><br/>'+
'<p>website</p>'+
'<input name="website"><br/>'+
'<button type="submit">submit</button>'+
'</form>'
ctx.body = html;
}else if(ctx.url === '/' && ctx.method === 'POST'){
// 使用中间件后,可以用ctx.request.body获取已经解析成json形式的请求结果
let postData = ctx.request.body;
ctx.body = postData;
}else{
ctx.body = '<h1>404</h1>'
}
})
app.listen(3000,() => {
console.log("server is starting at port 3000");
})

如何安装中间件koa-bodyparser ?

npm install --save koa-bodyparser@3

如何使用中间件koa-bodyparser ?

1.require进行引入

1
const bodyParser = require('koa-bodyparser');

2.然后进行使用,如果不使用是没办法调用的

1
app.use(bodyParser());

3.最后可以直接通过ctx.request.body 获取json格式的请求结果。

二、中间件

1.什么是中间件?

中间件处在 HTTP Request 和 HTTP Response 中间,用来实现某种中间功能。app.use()用来加载中间件。

基本上,Koa 所有的功能都是通过中间件实现的。每个中间件默认接受两个参数,第一个参数是 Context 对象,第二个参数是next函数。只要调用next函数,就可以把执行权转交给下一个中间件。

2.koa-bodyparser中间件原理:

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
function parsePostData(ctx) {
return new Promise((resolve,reject) => {
try{
let postdata = '';
ctx.req.addListener("data",(data) => {
postdata += data;
});
ctx.req.on('end',()=>{
let parseData = parseQueryStr(postdata);
resolve(parseData);
})
}catch(error){
reject(error);
}
})
}

// 将字符串转换为json对象
function parseQueryStr(queryStr) {
let queryData = {};
let queryStrList = queryStr.split("&");
for(let [index,queryStr] of queryStrList.entries()){
let itemList = queryStr.split("=");
// 网站:https%3A%2F%2Fhehuiyun.github.io%2F 使用 decodeURIComponent() 对编码后的 URI 进行解码:
queryData[itemList[0]] = decodeURIComponent(itemList[1]);
}
return queryData
}

decodeURIComponent是什么作用?

使用 encodeURIComponent() 对 URI 进行编码。

使用 decodeURIComponent() 对编码后的 URI 进行解码。

1
2
3
var test1="http://www.baidu.com"
document.write(encodeURIComponent(test1)+ "<br />")
document.write(decodeURIComponent(test1))

结果:

1
2
http%3A%2F%2Fwww.baidu.com<br />
http://www.baidu.com

3.合成中间件

koa-compose模块可以将多个中间件合成为一个。

安装koa-compose:npm install koa-compose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Koa = require('koa');
const compose = require('koa-compose');
const app = new Koa();

const logger = (ctx, next) => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
next();
}

const main = ctx => {
ctx.response.body = 'Hello World';
};

const middlewares = compose([logger, main]);

app.use(middlewares);
app.listen(3000);

三、路由

1.原生方法简单实现路由

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const Koa = require("koa");
const app = new Koa();

const fs = require('fs');

// render方法
function render(page) {
return new Promise((resolve,reject)=>{
// let pageUrl = './page/'+ page; //es5写法
let pageUrl = `./page/${page}`; //es6写法
fs.readFile(pageUrl,'binary',(err,data)=> {
if(err){
reject(err);
}else{
resolve(data);
}
});
})
}

// 原生实现路由
async function route(url) {
let page = '404.html';
switch(url){
case '/':
page= 'index.html';
break;
case '/index':
page="index.html";
break;
case '/todo':
page='todo.html';
break;
case '/404':
page= '404.html';
break;
default:
break;
}
let html = await render(page);
return html;
}

// 根据不同的url,返回相应的HTML
app.use(async (ctx) => {
let url = ctx.request.url;
let html = await route(url);
ctx.body = html;
});
app.listen(3000,(ctx)=> {
console.log("server is starting at port 3000");
})

2.设置路由

(1)设置前缀,全局改变路径(所有路径前都要加路径)

原来:http://127.0.0.1:3000/ 打开时,页面显示hello ;

​ http://127.0.0.1:3000/todo 打开时,页面显示todo page 。

设置前缀后:

http://127.0.0.1:3000/ http://127.0.0.1:3000/todo 显示Not Found ;

http://127.0.0.1:3000/whittney/ 打开时,页面显示hello ;

http://127.0.0.1:3000/whittney/todo 打开时,页面显示todo page 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Koa = require("koa");
const app = new Koa();
const Router = require("koa-router");
const router = new Router({
prefix: '/whittney'
});

router
.get('/',(ctx,next)=>{
ctx.body = 'hello';
})
.get('/todo',(ctx,next)=>{
ctx.body = 'todo page';
})
app.use(router.routes()).use(router.allowedMethods());

app.listen(3000,(ctx) => {
console.log("server is starting at port 3000!");
})

(2)单个页面前加路径

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
const Koa = require("koa");
const Router = require("koa-router");
const app = new Koa();
const router = new Router(); //父路由

let home = new Router();
home.get('/whittney',async(ctx) =>{
ctx.body = 'home whittney page';
})
.get('/todo',async(ctx) => {
ctx.body = 'home todo page';
})

let test = new Router();
test.get('/testpage',async(ctx)=>{
ctx.body = 'test page';
})

// 装载所有子路由
router.use('/home',home.routes(),home.allowedMethods());
router.use('/home/test',test.routes(),test.allowedMethods());

// 加载路由中间件
app.use(router.routes())
.use(router.allowedMethods());
app.listen(3000,(ctx)=>{
console.log("server is starting at port 3000");
})

给出各个路径:

home whittney page: http://127.0.0.1:3000/home/whittney

home todo page: http://127.0.0.1:3000/home/todo

test page: http://127.0.0.1:3000/home/test/testpage

加载资源和相关依赖库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// resources

var koa = require('koa')
var app = koa()

var logger = require('koa-logger')
var route = require('koa-route')

var fs = require('fs')
var path = require('path')
var extname = path.extname

var views = require('co-views')
var render = views('./views', {
map: { html: 'ejs' }
})

var model = require('./lib/model')

其中:

  1. koa 是最核心的库,app 是 koa 生成的 web 服务主程序;
  2. koa-logger 和 koa-route 都是koa官方开发的“中间件”,分别用来打印日志和路由设置;
  3. fs 和 path 都是 Node 的官方包,用来进行本地文件和路径相关的处理,辅助性质的;
  4. co-views 是用来渲染模板的库,而 render 是它生成的实例。

参考资料:

http://jspang.com/post/koa2.html

http://www.ruanyifeng.com/blog/2017/08/koa.html

赏

谢谢你请我吃糖果

  • koa

扫一扫,分享到微信

微信分享二维码
HTML5和微信小程序写页面的区别
自定义音频播放器的实现
© 2022 Whittney He
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • Adobe photoshop CC 2017
  • JS
  • 小程序
  • Typora
  • MYSQL
  • bootstrap
  • css
  • HTML+CSS+JS
  • jQuery
  • viewport
  • Vue.js
  • CSS3
  • Vue
  • CSS
  • h5
  • JS+jQuery
  • Clipboard.js
  • HTML+CSS+Jquery
  • 工具
  • 浏览器
  • css3
  • video
  • koa
  • ajax
  • cropper.js
  • 安全
  • vue.js
  • vue
  • js
  • javascript
  • echarts

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 友情链接1
  • 友情链接2
  • 友情链接3
  • 友情链接4
  • 友情链接5
  • 友情链接6
Whittney
我就是我,不一眼的烟火!*_*