Koa 是一个新的 web 框架 , 致力于成为 web 应用 和 API 开发 领域中的一个更小、更富有 表现力、更健壮的基石。
koa是Express的下一代基于Node.js的web框架
koa2完全使⽤用Promise并配合async来实现异步
Koa中间件机制:Koa中间件机制就是函数式 组合概念 Compose的概念,将一组需要顺序执⾏的 函数复合为一个函数,外层函数的参数实际是内层函数的返回值。洋葱圈模型可以形象表示这种机 制
中间件机制、请求、响应处理
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next) => {
ctx.body = [
{
name: 'tom'
}
]
next()
})
app.use((ctx, next) => {
console.log('url' + ctx.url)
if (ctx.url === '/html') {
ctx.type = 'text/html;charset=utf-8'
ctx.body = `<b>我的名字是:${ctx.body[ 0 ].name}</b>`
}
})
app.listen( 3000 )
常见的中间件操作:
静态服务
app.use(require('koa-static')(__dirname + '/'))
路由
const router = require('koa-router')()
router.get('/string', async (ctx, next) => {
ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
ctx.body = {
title: 'koa2 json'
}
})
app.use(router.routes())
日志:
app.use(async (ctx,next) => {
const start = new Date().getTime()
console.log(`start: ${ctx.url}`);
await next();
const end = new Date().getTime()
console.log(`请求${ctx.url}, 耗时${parseInt(end-start)}ms`)
})
koa 原理:一个基于node.js的入门级http服务
const http = require('http')
const server = http.createServer((req, res)=>{
res.writeHead(200)
res.end('hi tom')
})
server.listen(3000,()=>{
console.log('监听端口3000')
})
koa的目标是⽤用更简单化、流程化、模块化的方式实现回调部分
// 创建bg.js
const http = require("http");
class BG {
listen(...args) {
const server = http.createServer((req, res) => {
this.callback(req, res);
});
server.listen(...args);
}
use(callback) {
this.callback = callback;
}
}
module.exports = BG;
// 调⽤,app.js
const BG = require("./bg");
const app = new BG();
app.use((req, res) => {` `
res.writeHead( 200 );
res.end("ok");
});
app.listen( 3000 , () => {
console.log("监听端口3000");
});
context
koa为了能够简化API,引入上下文context概念,将原始请求对象req和响应对象res封装并挂载到context上,并且在context上设置getter和setter,从而简化操作。
// app.js
app.use(ctx=>{
ctx.body = 'hehe'
})
const context = require("./context");
const request = require("./request");
const response = require("./response");
class BG{
listen(...args) {
const server = http.createServer((req, res) => {
// 创建上下⽂文
let ctx = this.createContext(req, res);
this.callback(ctx)
// 响应
res.end(ctx.body);
});
// ...
}
// 构建上下⽂, 把res和req都挂载到ctx之上,并且在ctx.req和ctx.request.req同时保存
createContext(req, res) {
const ctx = Object.create(context);
ctx.request = Object.create(request);
ctx.response = Object.create(response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
}
常见koa中间件的实现
koa中间件的规范:
-
一个async函数
-
接收ctx和next两个参数
-
任务结束需要执⾏行行next
-
中间件常见任务:
-
请求拦截
-
路由
-
日志
-
静态文件服务
-
class BG {
// 初始化中间件数组
constructor() {
this.middlewares = [];
}
listen(...args) {
const server = http.createServer(async (req, res) => {
const ctx = this.createContext(req, res);
// 中间件合成
const fn = this.compose(this.middlewares);
// 执⾏合成函数并传⼊上下⽂
await fn(ctx);
res.end(ctx.body);
});
server.listen(...args);
}
use(middleware) {
// 将中间件加到数组⾥
this.middlewares.push(middleware);
}
// 合成函数
compose(middlewares) {
return function(ctx) { // 传⼊上下⽂
return dispatch( 0 );
function dispatch(i) {
let fn = middlewares[i];
if (!fn) {
return Promise.resolve();
}
return Promise.resolve(
fn(ctx, function next() {// 将上下文传入中间件, mid(ctx,next)
return dispatch(i + 1 );
})
);
}
};
}
createContext(req, res) {
let ctx = Object.create(context);
ctx.request = Object.create(request);
ctx.response = Object.create(response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}
}
module.exports = BG;
routes()的返回值是一个中间件,由于需要用到method,所以需要挂载method到ctx之上,修改request.js
// request.js
module.exports = {
// add...
get method(){
return this.req.method.toLowerCase()
}
}
// context.js
module.exports = {
// add...
get method() {
return this.request.method
},
}
class Router {
constructor() {
this.stack = [];
}
register(path, methods, middleware) {
let route = {path, methods, middleware}
this.stack.push(route);
}
get(path,middleware){
this.register(path, 'get', middleware);
}
post(path,middleware){
this.register(path, 'post', middleware);
}
routes() {
let stock = this.stack;
return async function(ctx, next) {
let currentPath = ctx.url;
let route;
for (let i = 0 ; i < stock.length; i++) {
let item = stock[i];
if (currentPath === item.path && item.methods.indexOf(ctx.method) >= 0 ) {
// 判断path和method
route = item.middleware;
break;
}
}
if (typeof route === 'function') {
route(ctx, next);
return;
}
await next();
};
}
}
module.exports = Router;
使用:
const Koa = require('./bg')
const Router = require('./router')
const app = new Koa()
const router = new Router();
router.get('/index', async ctx => {
console.log('index,xx')
ctx.body = 'index page';
});
router.get('/post', async ctx => { ctx.body = 'post page'; });
router.get('/list', async ctx => { ctx.body = 'list page'; });
router.post('/index', async ctx => { ctx.body = 'post page'; });
// 路由实例输出父中间件 router.routes()
app.use(router.routes());
app.listen( 3000 ,()=>{
console.log('server runing')
})
-
静态⽂文件服务koa-static
-
配置绝对资源⽬目录地址,默认为static
-
获取⽂文件或者⽬目录信息
-
静态⽂文件读取
-
返回
-