Koa尝试

171 阅读5分钟

--基于Node.js平台的下一代web开发框架

简介

  • Koa是一个新的web框架,是Express的升级版。通过利用async函数,Koa帮你丢弃回调函数,能有力地增强错误处理。Koa 并没有捆绑任何中间件,而是提供了一套方法,能够快速地编写服务端应用程序。

安装

!! 注意:koa依赖node v7.6.0或ES2015及更高版本和async方法支持

配置

    - $ npm install 7
    - $ npm i koa
    - $ node my-koa-app.js

应用程序

  • Koa应用程序是一个包含一组中间件函数的对象,它按类似堆栈的方式组织和执行,它其中的一个关键点在于其低级中间件层中提供高级'语法糖'。(个人理解是封装了很多中间件的使用函数,并没有引入那些中间件)
const Koa=require('koa');
const app=new Koa();
app.use(async ctx=>{   //ctx是request,response,next的集合体
    ctx.body='hello world';
});
app.listen(3000);  //app.listen()跟epxress中listen()的使用相同

级联

  • Koa 中间件以更传统的方式级联,之前难以使用 node 的回调,然而使用 async 功能,可以实现 “真实” 的中间件。对比 Connect 的实现,通过一系列功能直接传递控制,直到一个返回,Koa 调用“下游”,然后控制流回“上游”。

  • 下面以 “Hello World” 的响应作为示例,当请求开始时首先请求流通过 x-response-time 和 logging 中间件,然后继续移交控制给 response 中间件。当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。

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

// logger
//anync->await用法就是ES6的Generator的语法糖
app.use(async (ctx, next) => {
  await next();    //到这里暂停,执行下一个中间件 
  const rt = ctx.response.get('X-Response-Time');
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time

app.use(async (ctx, next) => {
  const start = Date.now();
  await next();   //到这里暂停,执行下一个中间件
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});

// response

app.use(async ctx => {
  ctx.body = 'Hello World';
});
//主线程里中间件执行完,执行顺序变成'回流'由下往上执行await next()后面的内容

app.listen(3000);

设置

  • 应用程序设置是app实例上的属性,目前支持这些

    • app.env 默认是NODE_ENV或"development"
      • 这里打印console.log(app);
      • 得到的是一个对象 { subdomainOffset : 2 , proxy : false , env : 'development' }
      • domain是域名的意思,subdomainOffset我觉得应该是端口有几个的意思,毕竟下面有说app.listen()可以重复使用开启多个端口
      • proxy:false指的是代理,false表示代理没开,前端的代理指的是解决跨域问题
      • env表示环境,目前是开发环境
        • 开发环境 代码开发阶段所处的环境
        • 生成环境 开发阶段的代码经过编译,压缩后文件运行的环境
        • 测试环境 开发阶段的代码经过编译,压缩后文件进行代码质量检测,语法检测
        • 上线环境 处理后放在服务器或主机中运行
    • app.keys 签名的cookie密钥数组
    • app.proxy 当真正的代理头字段被信任时 //应该是代理或者转发的意思
    • app.subdomainOffset对于要忽略的.subdomains偏移[2] //这句话没看懂
  • 可以将设置传递给构造函数

    const Koa=require('koa');
    const app=new Koa({proxy:true});
  • 或者动态的
    const Koa = require('koa');
    const app = new Koa();
    app.proxy = true;
  • app.listen(...)

    • Koay应用程序不是HTTP服务器1对1展现,可以将一个或多个Koa应用程序安装在一起以形成具有单个HTTP服务器的更大应用程序
        //其实就是可以放多个的意思,一个js文件创建多个端口,这些可以通过请求不同端口访问设置相同的响应
        app.listen(3000);
        app.listen(3001);
        app.listen(3002);
        
        //上面的app.listen(...)方法只是下面的语法糖
        const http = require('http');
        const Koa = require('koa');
        const app = new Koa();
        http.createServer(app.callback()).listen(3000); //httph和https请求都可以设置
    
  • app.callback()

    • 返回适用于 http.createServer()方法的回调函数来处理请求。你也可以使用此回调函数将 koa 应用程序挂载到 Connect/Express 应用程序中。
  • app.use(function)

    • 将给定的中间件方法添加到此应用程序,详情记得查阅手册
  • app.keys=

    • 设置签名的Cookie密钥
    • 这些被传递给KeyGrip,但是也可以传递自己的KeyGrip实例
    app.keys = ['im a newer secret', 'i like turtle'];
    app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');
    
    • 这些密钥可以倒换,并在使用{signed:true}参数签名Cookie时使用
    ctx.cookies.set('name','tobi',{signed:true});
    
  • app.context

    • app.context是从其创建ctx的原型。可以通过编辑app.context为 ctx 添加其他属性。这对于将ctx添加到整个应用程序中使用的属性或方法非常有用,这可能会更加有效(不需要中间件)和/或 更简单(更少的require()),而更多地依赖于ctx,这可以被认为是一种反模式
    app.context.db=db();
    app.use(async ctx=>{
        console.log(ctx.db);
    })
    
    • 注意:安装的应用程序目前使用其父级的 ctx和设置,这就是之前说的一组中间件 github.com/koajs/koa/i…
  • 错误处理

    • 默认情况下,将所有错误输出到stderr,除非app.silent为true,当err.status是404或err.expose是true时默认错误处理程序也不会输出错误。要执行自定义错误处理逻辑,如集中式日志记录,可以添加一个'error'事件侦听器
    app.on('error',err=>{
        log.error('server error',err);
    })
    
    • 如果req/res期间出现错误,并且无法响应客户端,Context实例仍然被传递
    app.on('error',(err,ctx)=>{
        log.error('server error',err,ctx);
    })
    
    • 当发生错误,但是可以响应客户端时,也没有数据被写入socket中,Koa将用一个500"内部服务器错误"进行适当的响应,在任意情况下,为了记录目的,都会发出应用级错误

上下文(Context)

  • KoaContext将node的request和response对象封装到单个对象中,为编写Web应用程序和API提供了许多有用的方法,这些操作在HTTP服务器开发中频繁使用,他们被添加到此级别而不是更高级别的框架,这将强制中间件重新实现此通用功能
  • 每个请求都将创建一个Context,并在中间件中作为接收器引用,或者ctx标识符
   app.use(async ctx =>{
       ctx; //这是Context
       ctx.request;//这是koa Request
       ctx.response;//这是koa Response
   })
  • 为方便起见许多上下文的访问器和方法直接委托给它们的 ctx.request或 ctx.response ,不然的话它们是相同的。 例如 ctx.type 和 ctx.length 委托给 response 对象,ctx.path 和 ctx.method 委托给 request。

API

  • ctx.req -> node的request对象

  • ctx.res -> node的response对象

    • 这里有说避免使用node的
    • res.statusCode
    • res.writeHead()
    • res.write()
    • res.end()
  • ctx.state 推荐的命名空间,用于通过中间件传递信息和你的前端视图

    • ctx.state.user = await User.find(id); //数据库查询,没看懂是想表达什么意思
  • ctx.app.emit()

    • Koa制定的事件触发方法,自定义事件用的就是node.js的自定义事件方法,emit方法也是延续的node.js的events模块的方法
    ctx.app.on('aa',function(){
        console.log('hello word');
    });
    ctx.app.emit('aa');
    
  • ctx.cookies.get(name,[options])

    • 通过options 获取cookie的name,signed所请求的cookie应该被签名,koa使用cookies模块,其中只需传递参数
  • ctx.cookies.set(name,value,[options])

    • 通过options 设置cookie name的value
    • maxAge一个数字表示从Date.now()得到的毫秒数
    • signed cookie签名值
    • expires cookie国企的Date
    • path cookie路径,默认是'/'
    • domain cookie域名
    • secure 安全 cookie
    • httpOnly 服务器可访问 cookie, 默认是 true
    • overwrite 一个布尔值,表示是否覆盖以前设置的同名的 cookie (默认是 false). 如果是 true, 在同一个请求中设置相同名称的所有 Cookie(不管路径或域)是否在设置此Cookie 时从 Set-Cookie 标头中过滤掉。