Koa

参考资料

Koa

环境部署

下载安装NodeJS

下载地址: http://nodejs.cn/download/

$ node -v
v10.15.0

$ npm -v
6.4.1

Koa2

官网:https://koa.bootcss.com/

Koa是基于Node.js平台的下一台Web开发框架,Koa是一个全新的Web框架,由Express原班人马打造,致力于成为Web应用和API开发领域中更小且更加富有表现力、更健壮的基石。通过async函数Koa帮你丢弃回调函数,并有力地增强错误处理。Koa并没有绑定任何中间件,而是提供了一套优雅的方法帮助快速编写服务器端应用程序。

Koa2相比较Koa1最大区别在于中间件的写法,Koa1使用Generator,Koa2使用async/await语法,因此Node.js必须大于v7.6.0+。

安装

Koa依赖Node v7.6.0 或ES2015+ 和 async方法支持。

创建工程文件夹并进入,使用npm初始化项目。

# 手工创建项目
$ mkdir project && cd  project

# 快速生成package.json文件
$ npm init -y

$ vim package.json
{
  "name": "project",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start":"node app.js" // 添加快捷启动命令
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
  }
}

运行脚本

可直接使用node app.js运行脚本,也可以使用它的快捷方式npm start运行app.js脚本。

$ node app.js
$ npm start

安装Koa

$ npm install koa -S
$ npm i koa

应用程序

Koa应用程序是一个包含一组中间件函数的对象,它按照类似堆栈的方式组织和执行。Koa类似中间件系统。

$ vim app.js

导入Koa,在Koa2中由于导入的是一个类,所以使用大写的Koa。

const Koa = require("koa");

创建Koa对象,即Web应用本身app

const app = new Koa();

对于任何HTTP请求,app将调用异步函数进行处理。

app.use(async (ctx, next)=>{
  await next();
  // 设置HTTP响应的内容类型
  ctx.response.type = "text/html";
  // 设置HTTP响应的内容
  ctx.response.body = "hello world";
});

每当Koa收到一个HTTP请求时,会调用通过app.use()注册的async异步函数并传入ctxnext参数。可以针对ctx进行操作并设置返回内容。

async标记的函数称为异步函数,使用await调用另一个异步函数,async/await关键字是在ES7中引入的。

ctx是Koa提供的Context对象,封装了requestresponse对象,每次HTTP Request都会创建一个Context上下文对象。

ctx是由Koa传入的封装了requestresponse的变量,可通过ctx.requestctx.response访问请求和响应。

中间件

next是Koa传入将要处理的下一个异步函数,await next();表示处理下一个异步函数,然后再设置response响应的Content-Typebody内容。

await next();有什么作用呢?

Koa将多个async异步函数组成了一个处理链,每个async异步函数都可以做自己的事情,然后使用await next()来调用下一个async异步函数。这里将每个async异步函数成为中间件middleware,这些中间件可以组合起来完成很多实用的功能。

监听3000端口

app.listen(3000);

浏览器访问:http://127.0.0.1:3000

JS异步发展史

  • ES5:回调函数callback
  • ES6:Promise对象和Generator函数
  • ES7:async/await语法

async/await

async用于声明一个函数是异步的,await只能出现在async修改的函数中。async函数会返回一个promise对象,如果在async函数返回一个直接量它最终将通过Promise.resolve封装成promise对象,进而可以直接通过promise对象的then方法来获取这个直接量。

await会暂停当前async的执行,await会阻塞代码的执行直到await后的表达式处理完毕,代码才继续往下执行。await后的表达式可以是一个promise对象也可以任何需要等待的值。如果await等到的是一个promise对象,await就会阻塞后续代码直到promise对象resolve后得到resolve的值作为await表达式的运算结果。

async/await只是一种语法糖,其代码执行与回调函数嵌套是本质上是没有区别的,只是写法上让人以同步的思维去思考,避开回调地狱。简而言之,async/await是以同步的思维去编写异步的代码,所以async/await并不会影响Node.js的并发数。

中间件

中间件类似于过滤器,用于在客户端和应用程序之间处理请求和响应的方法。中间件的执行类似剥洋葱,但并非一层层的执行,而是以next为分界,先执行本层next之前的部分,当下一层中间件执行完毕后再执行本层next之后的部分。

中间件

中间件是为了解决复杂应用中频繁回调而设计的级联式代码,它并不直接将控制权完全交给下一个中间件,而是碰到next后去下一个中间件,等到下面都执行完毕后在执行next后续代码。

例如:使用三个中间件组成处理链,依次打印日志,记录处理时间,输出HTML。

//中间件处理链
app.use(async (ctx, next) => {
    console.log(`${ctx.request.method} ${ctx.request.url}`);
    await next();//调用下一个中间件
});
app.use(async (ctx, next) => {
    const begin_time = new Date().getTime();
    await next();//处理下一个中间件
    const spend_ms = new Date().getTime() - begin_time;//耗费时间
    console.log(`Time: ${spend_ms}ms`);
});
app.use(async (ctx, next) => {
    await next();
    ctx.response.type = "text/html";
    ctx.response.body = "request received";
});

注意中间件的顺序也就是调用app.use()的顺序将决定了中间件的执行顺序。如果某个中间件没有调用await next()则后续中间件将不再执行。

例如:检测用户权限的中间件可以决定是否继续处理请求,若不则直接返回403错误。

app.use(async (ctx, next) => {
    if(await checkAuth(ctx)){
        await next();
    }else{
        ctx.response.status = 403;
    }
});

简单来说,理解了中间件也就学会使用Koa了。

获取GET请求数据

Koa2中GET请求可通过ctx.request接收,接收方式分为两种:

  • ctx.request.query 获取格式化后的参数对象
  • ctx.request.querystring 获取请求字符串
  • ctx.query
  • ctx.querystring

例如:

app.use(async (ctx, next) => {
    const url = ctx.url;
    //使用ctx.request接收
    const rq = ctx.request;
    const rq_query = rq.query;
    const rq_qs = rq.querystring;
    //使用ctx接收
    const ctx_query = ctx.query;
    const ctx_qs = ctx.querystring;

    //返回
    body = {};
    body.rq_query = rq_query;
    body.rq_qs = rq_qs;
    body.ctx_query = ctx_query;
    body.ctx_qs = ctx_qs;
    ctx.body = body;
});

获取POST请求数据

Koa2中没有对POST请求的处理封装获取参数的方法,需要通过解析上下文ctx中的元素来获取,具体可分为三步:

  1. 解析上下文ctx对象中的原生Node.js对象req
  2. 将POST表单数据解析为querystring查询字符串
  3. 将查询字符串转换为JSON格式
const Koa = require("koa");
const app = new Koa();

const parseQueryString = (querystring) => {
    const queryData = {};
    const qsList = querystring.split("&");
    for(let [index, qs] of qsList.entries()){
        let kvList = qs.split("=");
        queryData[kvList[0]] = decodeURIComponent(kvList[1]);
    }
    return queryData;
};

const parsePostData = (ctx) => {
    return new Promise((resolve, reject) => {
        try{
            let postData = "";
            ctx.req.on("data", (data)=>{
                postData += data;
            })
            ctx.req.addListener("end", ()=>{
                let parseData = parseQueryString(postData);
                resolve(parseData);
            });
        }catch(error){
            reject(error);
        }
    });
};

app.use(async(ctx, next) => {
    if(ctx.method === "POST"){
        let postData = await parsePostData(ctx);
        ctx.body = postData;
    }
});

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

另一种方式是使用koa-bodyparser中间件,对于POST请求的处理,koa-bodyparser中间件可以将Koa上下文中的formData数据解析到ctx.request.body中。

koa-bodyparser

安装

$ npm i koa-bodyparser -S

使用

const Koa = require("koa");
const app = new Koa();

const bodyParser = require("koa-bodyparser");
app.use(bodyParser());

app.use(async(ctx, next) => {
    if(ctx.method === "POST"){
        ctx.body = ctx.request.body;
    }
});

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

supervisor

使用supervisor自动重启模块

$ npm i supervisor -g
# 修改package.json,设置scripts选项下的start。
"scripts":
{
    "test": "echo \"Error: no test specified\" && exit 1",
    "start":"supervisor app.js" //设置npm start启动项
}

koa-router

koa-router 路由组件

$ npm i koa-router -S
var Koa = require("koa");
var app = new Koa();
var router = require("koa-router")();

router.get("/", (ctx, next) => {
  console.log("homepage");
});

app.use(router.routes()).use(router.allowedMethods());

参考资料

koa-router是Koa的路由组件,路由的功能是指定具体的访问路径,通过访问路径指向特定的功能模块。

安装

# 安装Koa
$ npm install koa --save

# 安装koa-router
$ npm install koa-router --save

使用

var Koa = require("koa");
var Router = require("koa-router");

var app = new Koa();
var router = new Router();

app.use(router.routes()).use(router.allowedMethods());

router.get("/", (ctx, next)=>{

});

koa-simple-router

路由koa-simple-router

$ npm i koa-simple-router -S

koa-cors 跨域组件

安装

$ npm install --save koa2-cors

使用

var Koa = require('koa');
var cors = require('koa2-cors');

var app = new Koa();
app.use(cors());

koa-static

koa-static为原生koa2实现静态资源服务器

一个HTTP请求访问Web服务静态资源,一般响应结果有3种情况:

  • 访问文本,如css、js、image...
  • 访问静态目录
  • 找不到资源则抛出404错误

为Koa2实现静态资源加载的服务,用于访问css/js/img等静态资源,若访问图片则返回二进制,其他文件则直接输出字符串。

$ npm i koa-static -S
# 设置static目录用于存储静态资源,app.js添加中间件。
app.use(require("koa-static")(__dirname + "/static"));

koa-views

koa-views为Koa2加载的模板引擎

$  npm i koa-views -S

根目录下创建views目录用于存储视图模板文件,并在app.js文件中添加中间件配置。

//模板引擎
app.use(require("koa-views")(__dirname+"/views"));

koa-logger

//日志配置
app.use(require("koa-logger")());

koa-bodyparser

$ npm i koa-bodyparser@2 -S
app.use(require("koa-bodyparser")())

koa-session

$ npm i koa-session -S

mongoose

https://mongoosejs.com

$ npm i mongoose -S

config


$ npm i config -S

mysql

mysql模块是node操作MySQL的引擎,可在node.js环境下对MySQL数据库进行CURD等操作。

$ npm i mysql -S
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容