参考资料
环境部署
下载安装NodeJS
下载地址: http://nodejs.cn/download/
$ node -v
v10.15.0
$ npm -v
6.4.1
Koa2
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
异步函数并传入ctx
和next
参数。可以针对ctx
进行操作并设置返回内容。
由async
标记的函数称为异步函数,使用await
调用另一个异步函数,async/await
关键字是在ES7中引入的。
ctx
是Koa提供的Context对象,封装了request
和response
对象,每次HTTP Request都会创建一个Context上下文对象。
ctx
是由Koa传入的封装了request
和response
的变量,可通过ctx.request
和ctx.response
访问请求和响应。
中间件
next
是Koa传入将要处理的下一个异步函数,await next();
表示处理下一个异步函数,然后再设置response
响应的Content-Type
和body
内容。
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
中的元素来获取,具体可分为三步:
- 解析上下文
ctx
对象中的原生Node.js对象req
- 将POST表单数据解析为
querystring
查询字符串 - 将查询字符串转换为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
$ npm i mongoose -S
config
$ npm i config -S
mysql
mysql
模块是node操作MySQL的引擎,可在node.js环境下对MySQL数据库进行CURD等操作。
$ npm i mysql -S