node.js 框架koa详解

再次思考:从浏览器输入 URL 到页面展示过程的过程中发生了什么?通过前面的基础学习,我们了解了基于 Web 的应用基本流程:通过上图不难发现,无论具体应用功能如何变化, 服务端 处理任务核心三个步骤:③、④、⑤ 中,③ 和 ⑤ 的模式基本是固定的(因为HTTP协议规范了),而 ④ 是最大的变量。如果我们每次开发一个新的应用都要把 ③ 和 ⑤ 的逻辑重新实现一遍就会特别的麻烦。所以,我们可以封装一个框架(库)把 ③ 和 ⑤ 的逻辑进行统一处理,然后通过某种方式,把 ④ 的处理暴露给框架使用者。e.
摘要由CSDN通过智能技术生成

再次思考:从浏览器输入 URL 到页面展示过程的过程中发生了什么?

通过前面的基础学习,我们了解了基于 Web 的应用基本流程:

通过上图不难发现,无论具体应用功能如何变化, 服务端 处理任务核心三个步骤:③、④、⑤ 中,③ 和 ⑤ 的模式基本是固定的(因为HTTP协议规范了),而 ④ 是最大的变量。

如果我们每次开发一个新的应用都要把 ③ 和 ⑤ 的逻辑重新实现一遍就会特别的麻烦。所以,我们可以封装一个框架(库)把 ③ 和 ⑤ 的逻辑进行统一处理,然后通过某种方式,把 ④ 的处理暴露给框架使用者。

egg.js

nest.js

nodemon的局部安装与快捷键

// 局部安装 开发模式
npm i nodemon -D

// 快捷启动方式,package.json文件里scripts下配置快捷键名称
"scripts": {
    "aaa": "nodemon app.js"
  }

// 快捷启动
npm run aaa

Koa

资源:

官网:https://koajs.com/

中文:https://koa.bootcss.com/

  • 基于 NodeJS 的 web 框架,致力于 web 应用和 API 开发。
  • 由 Express 原班人马打造。
  • 支持 async。
  • 更小、更灵活、更优雅。

安装

当前最新 Koa 依赖 node v7.6.0+、ES2015+ 以及 async 的支持。

具体请关注官网说明(依赖会随着版本的变化而变化)。

参考:https://koajs.com/#introduction

// 创建一个package.json文件
npm init
npm init -y

// 安装 koa
npm i koa

// 或者
yarn add koa

核心

KoaNodeJS 原生 IncomingMessageServerResponse 对象和解析响应通用流程进行了包装,并提供了几个核心类(对象)用于其它各种用户业务调用。

  • Application 对象
  • Context 对象
  • Request 对象
  • Response 对象

应用代码

/**
 * File: /app.js
***/

const Koa = require('koa');

const app = new Koa();

app.listen(8888);

Application 对象

该对象是 Koa 的核心对象,通过该对象来初始化并创建 WebServer

/**
 * File: /node_modules/koa/lib/application.js
***/

constructor(options) {
   
  super();
  options = options || {
   };
  this.proxy = options.proxy || false;
  this.subdomainOffset = options.subdomainOffset || 2;
  this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
  this.maxIpsCount = options.maxIpsCount || 0;
  this.env = options.env || process.env.NODE_ENV || 'development';
  if (options.keys) this.keys = options.keys;
  this.middleware = [];
  this.context = Object.create(context);
  this.request = Object.create(request);
  this.response = Object.create(response);
  if (util.inspect.custom) {
   
    this[util.inspect.custom] = this.inspect;
  }
}

构造函数对 Application 创建进行了一些初始化工作,暂时不需要关注这里的太多细节,后续关注。

应用代码

/**
 * File: /app.js
***/

const Koa = require('koa');

const app = new Koa();

listen 方法

WebServer 并不是在 Application 对象创建的时候就被创建的,而是在调用了 Application 下的 listen 方法的时候在创建。

/**
 * File: /node_modules/koa/lib/application.js
***/

listen(...args) {
   
  debug('listen');
  const server = http.createServer(this.callback());
  return server.listen(...args);
}

通过源码可以看到,其本质还是通过 NodeJS 内置的 http 模块的 createServer 方法创建的 Server 对象。并且把 this.callback() 执行后的结果(函数)作为后续请求的回调函数。

/**
 * File: /node_modules/koa/lib/application.js
***/

callback() {
   
  const fn = compose(this.middleware);

  if (!this.listenerCount('error')) this.on('error', this.onerror);

  const handleRequest = (req, res) => {
   
    const ctx = this.createContext(req, res);
    return this.handleRequest(ctx, fn);
  };

  return handleRequest;
}

通过上述代码的分析,实际上请求执行的回调函数式 callback 返回的 handleRequest 函数,且该函数接收的 reqres 参数就是 NodeJSHTTP 模块内置的两个对象 IncomingMessageServerResponse 对象。其中:

const ctx = this.createContext(req, res);

这里, Koa 会调用 Application 对象下的 createContext 方法对 reqres 进行包装,生成 Koa 另外一个核心对象: Context 对象 - 后续分析。

return this.handleRequest(ctx, fn);

接着调用 Application 对象下的 handleRequest 方法进行请求处理,并传入:

  • ctx: 前面提到的 Context 对象。
  • fn: 这个实际上是 const fn = compose(this.middleware); 这段代码得到的是一个执行函数,这里又称为: 中间件函数

中间件函数

所谓的中间件函数,其实就是一开始我们提到的 ④,首先, Application 对象中会提供一个属性 this.middleware = []; ,它是一个数组,用来存储 ④ 需要处理的各种业务函数。这些业务函数会通过 Application 下的 use 方法进行注册(类似事件注册)。

为什么叫中间件

因为它是在 请求 之后, 响应 之前调用的函数,所以就叫它 中间件函数

响应流程处理

通过上述流程分析,可以看到,每一个请求都会执行到 Application 对象下的 handleRequest 方法。

/**
 * File: /node_modules/koa/lib/application.js
***/

handleRequest(ctx, fnMiddleware) {
   
  const res = ctx.res;
  res.statusCode = 404;
  const onerror = err => ctx.onerror(err);
  const handleResponse = () => respond(ctx);
  onFinished(res, onerror);
  return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}

这里的 fnMiddleware 就是一系列中间件函数执行后结果(一个 Promise 对象),当所有中间件函数执行完成以后,会通过 then 调用 handleResponse ,也就是调用了 respond 这个方法。

响应处理

/**
 * File: /node_modules/koa/lib/application.js
***/

function respond(ctx) {
   
  // allow bypassing koa
  if (false === ctx.respond) return;

  if (!ctx.writable) return;

  const res = ctx.res;
  let body = ctx.body;
  const code = ctx.status;

  // ignore body
  if (statuses.empty[code]) {
   
    // strip headers
    ctx.body = null;
    return res.end();
  }

  if ('HEAD' === ctx.method) {
   
    if (!res.headersSent && !ctx.response.has('Content-Length')) {
   
      const {
    length } = ctx.response;
      if (Number.isInteger(length)) ctx.length = length;
    }
    return res.end();
  }

  // status body
  if (null == body) {
   
    if (ctx.req.httpVersionMajor >= 2) {
   
      body = String(code);
    } else {
   
      body = ctx.message || String(code);
    }
    if (!res.headersSent) {
   
      ctx.type = 'text';
      ctx.length = Buffer.byteLength(body);
    }
    return res.end(body);
  }

  // responses
  if (Buffer.isBuffer(body
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值