Koa学习笔记(一)基础入门

274 阅读10分钟

1.认识Koa

1.1 Koa是什么

Koa 是一个轻量级、灵活的 Node.js Web 应用框架。它是由 Express 原班人马开发的,旨在为 Web 应用程序和 API 提供一个更优雅、更富有表现力的基础。相比于 Express,Koa 的设计更加简单和优雅。它摒弃了一些 Express 中的复杂功能,专注于提供一个更简洁、更灵活的 Web 开发框架。许多开发者认为 Koa 是 Express 的继任者,它更适合构建复杂的、可扩展的 Web 应用程序和 API。

1.2 可以用Koa来做什么

以下是一些常见的使用场景:

  1. Web 应用程序:
    • 使用 Koa 可以快速搭建出功能完备的 Web 应用程序,包括博客、电商网站、企业官网等。
    • Koa 的中间件机制允许开发者根据需求灵活地集成各种功能,如身份验证、模板引擎、静态资源服务等。
  2. API 服务:
    • Koa 非常适合构建 RESTful API 服务,可以轻松地处理 HTTP 请求、解析参数、生成 JSON 响应等。
    • 借助 Koa 的异步处理能力,开发者可以构建高性能的 API 服务,满足各种复杂的业务需求。
  3. 微服务架构:
    • 由于 Koa 的模块化和可扩展性,开发者可以将应用程序拆分成多个独立的微服务,提高系统的灵活性和可维护性。
    • Koa 可以与其他微服务框架如 Micro 或 Moleculer.js 等配合使用,构建复杂的微服务架构。
  4. 实时应用程序:
    • Koa 可以与 WebSocket 等实时通信技术相结合,开发实时聊天应用、协作编辑器、实时数据可视化等应用程序。
  5. 中间件开发:
    • Koa 本身就是一个中间件框架,开发者可以开发自己的 Koa 中间件,并在自己的应用程序或其他 Koa 应用中使用。
    • 社区中已经有许多优秀的 Koa 中间件可供选择和参考。
  6. 快速原型开发:
    • Koa 的简洁和灵活性使得它非常适合快速原型开发,开发者可以快速搭建出可工作的 Web 应用程序或 API 服务。

2. 快速开始

2.1 安装Koa

#创建项目文件夹
mkdir koa-project
# 定位到项目下
cd koa-project
# 初始化package.json
npm init
# 安装Koa 
npm install koa

2.2 创建index.js文件

在根目录下创建index.js文件,粘贴hello world 代码

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

app.use(async ctx => {
  ctx.body = 'Hello World';
});

app.listen(3000);

2.3 启动Koa服务

由于Koa是基于async/await操作中间件,目前node.js 7.x的harmony模式下才能使用,所以启动的时的脚本如下:

node index.js

2.4 热更新

每次在Koa中更新代码后想要生效必须重启koa服务,那如何热更新代码来帮助我们提高开发效率?

  1. 安装nodemon
   npm install nodemon
   npm i nodemon -g // 建议直接全局安装
  1. 修改package.js
"scripts": {
  "start": "nodemon index.js"
}

运行npm run start再次启动服务,这时修改代码后只需要刷新浏览器即可,不用重启node服务了!

3. 中间件

Koa 中间件是 Koa.js 框架中一个非常核心的概念。Koa 中间件主要用于以下几个方面:

  1. 请求处理:Koa 中的中间件可以对 HTTP 请求进行处理,包括解析请求参数、设置响应头、发送响应等操作。
  2. 错误处理:中间件可以捕获并处理应用程序中抛出的异常,提供友好的错误响应。
  3. 日志记录:中间件可以记录请求的相关信息,如 HTTP 方法、URL、状态码等,方便日后排查问题。
  4. 跨域支持:中间件可以设置 CORS 相关的响应头,允许前端跨域访问后端接口。
  5. 访问控制:中间件可以实现基于角色或权限的访问控制逻辑。
  6. 数据缓存:中间件可以对某些数据进行缓存,提高响应速度。
  7. 内容压缩:中间件可以对响应内容进行 Gzip 压缩,减小传输数据量。
  8. 请求校验:中间件可以对请求参数进行校验,确保输入的合法性。
  9. 认证授权:中间件可以实现用户的认证和授权功能。
  10. 其他功能:中间件可以根据实际需求提供各种其他功能,如服务监控、性能优化等。

Koa 中间件通过 app.use() 方法进行挂载。每个中间件函数接收 ctx 和 next 两个参数,ctx 代表当前请求的上下文对象,next 则用于调用下一个中间件。中间件的执行顺序遵循"洋葱模型",即先进后出。来看下洋葱模型的图:

onion.png

关于koa洋葱模型的源码分析可以戳这里[Node.js进阶系列]Koa源码分析之洋葱模型-github/webfansplz

这里,我们使用async await编写一个log的中间件

在根目录下创建目录middleware,在该目录下创建文件logger-async.js,填充内容如下:

function log( ctx ) {
    console.log( ctx.method, ctx.header.host + ctx.url )
}

module.exports = function () {
  return async function ( ctx, next ) {
    log(ctx);
    await next()
  }
}

在index.js里面文件引用下该文件并应用。

const Koa = require('koa');
const loggerAsync  = require('./middleware/logger-async')
const app = new Koa();

app.use(loggerAsync())

app.use(ctx => {
  ctx.body = 'Hello World !';
});

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000');
});

4. 路由搭建

手动处理路由需要处理很多代码,这里交给中间件去做,Koa-router 是 Koa 应用程序中非常重要的中间件,它提供了强大的路由管理功能,大幅简化了 Web 应用程序的开发和维护。

npm install --save koa-router

在根目录下创建view目录,在该目录下创建两个页面todo.html404.htmlindex.js修改如下:

const Koa = require('koa')
const fs = require('fs')
const app = new Koa()
const path = require('path');
const Router = require('koa-router')

//创建路由实例
let router = new Router()

// 首页
router.get('/', async (ctx) => {
  ctx.body = `
    <h1>Welcome to the Home Page</h1>
      <ul>
      <li><a href="/todo">/view/todo</a></li>
      <li><a href="/404">/view/404</a></li>
    </ul>
  `;
});

// 404 页面路由
router.get('/404', async (ctx) => {
  ctx.body = await fs.promises.readFile(path.join(__dirname, 'view', '404.html'), 'utf8');
});

// todo 页面路由
router.get('/todo', async (ctx) => {
  ctx.body = await fs.promises.readFile(path.join(__dirname, 'view', 'todo.html'), 'utf8');
});

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

app.listen(3000, () => {
  console.log('[demo] route-use-middleware is starting at port 3000')
}) 

image.png

点击后跳转到对应的html页面。

理解下app.use(router.routes()) 和 app.use(router.allowedMethods()) 这两行代码,在使用 Koa-router 时它们非常重要,作用如下:

  1. app.use(router.routes()):

    • 这行代码将路由中间件挂载到 Koa 应用程序上。
    • 它告诉 Koa 应用程序使用 Koa-router 定义的路由规则来处理请求。
    • 当客户端发起请求时,Koa 应用程序会根据这些路由规则进行匹配和分发。
  2. app.use(router.allowedMethods()):

    • 这行代码是对上一行的补充。
    • 它为每个路由添加了 HTTP 方法校验,确保请求方法与路由定义的方法匹配。
    • 如果请求方法不匹配,它会自动返回 405 Method Not Allowed 的 HTTP 状态码。
    • 这有助于确保应用程序的健壮性和安全性。

5. 数据请求

5.1 GET请求数据获取

对于 GET 请求,使用 ctx.query 或 ctx.request.query 是最简单和常见的方式。

  1. 通过 ctx.query 获取查询参数:

    • ctx.query 是一个包含所有查询参数的对象。
    • 例如,对于 http://example.com/api?name=John&age=30 这个 URL,ctx.query 将是 { name: 'John', age: '30' }.
router.get('/api', async (ctx) => {
  const { name, age } = ctx.query;
  ctx.body = `Name: ${name}, Age: ${age}`;
});
  1. 通过 ctx.request.query 获取查询参数:

    • ctx.request.query 与 ctx.query 作用相同,都是获取查询参数。
    • 使用 ctx.request.query 可以保持与 Node.js 原生 HTTP 模块的一致性。
router.get('/api', async (ctx) => {
  const { name, age } = ctx.request.query;
  ctx.body = `Name: ${name}, Age: ${age}`;
});

5.2 POST请求数据获取

对于POST请求的处理,koa2没有封装获取参数的方法,需要通过解析上下文context中的原生node.js请求对象req,将POST表单数据解析成query string(例如:a=1&b=2&c=3),再将query string 解析成JSON格式(例如:{"a":"1", "b":"2", "c":"3"}),处理起来有点繁琐。这里使用koa-bodyparser中间件,可以把koa2上下文的formData数据解析到ctx.request.body中。

npm install --save koa-bodyparser

使用:

const Koa = require('koa')
const app = new Koa()
const bodyParser = require('koa-bodyparser')

// 使用ctx.body解析中间件
app.use(bodyParser())

app.use( async ( ctx ) => {

  if ( ctx.url === '/' && ctx.method === 'GET' ) {
    // 当GET请求时候返回表单页面
    let html = `
    <form method="POST" action="/">
        <p>姓名</p>
        <input name="userName" /><br/>
        <p>昵称</p>
        <input name="nickName" /><br/>
        <p>邮件</p>
        <input name="email" /><br/>
        <button type="submit">提交</button>
      </form>
    `
    ctx.body = html
  } else if ( ctx.url === '/' && ctx.method === 'POST' ) {
    // 当POST请求的时候,中间件koa-bodyparser解析POST表单里的数据,并显示出来
    let postData = ctx.request.body
    ctx.body = postData
  } else {
    // 其他请求显示404
    ctx.body = '<h1>404!!! o(╯□╰)o</h1>'
  }
})

app.listen(3001, () => {
  console.log('[demo] request post is starting at port 3001')
})

image.png

补充:koa-bodyparser 提供了一些可配置项,可以根据需求进行设置:

app.use(bodyParser({
  // 是否支持 urlencoded 编码的请求体,默认为 true
  enableTypes: ['json', 'form', 'text'],

  // 设置请求体最大长度,默认为 56kb
  jsonLimit: '56kb',

  // 设置解析请求体的选项,可以参考 co-body 库的选项
  onerror: (err, ctx) => {
    // 处理解析错误
    ctx.throw(400, err);
  }
}));

6. 静态资源加载

一个http请求访问web服务静态资源,一般响应结果有三种情况

  • 访问文本,例如js,css,png,jpg,gif
  • 访问静态目录
  • 找不到资源,抛出404错误

这里直接推荐使用koa-static 中间件,它的主要作用就是提供静态文件服务。具体来说,koa-static 有以下几个主要功能:

  1. 静态文件服务:

    • koa-static 可以为你的 Koa 应用提供静态文件服务,如 HTML、CSS、JavaScript、图片等。
    • 当客户端请求某个静态资源时,koa-static 会自动从指定的目录中查找并返回对应的文件内容。
  2. 目录浏览:

    • koa-static 可以自动生成目录浏览页面,方便用户查看指定目录下的文件列表。
    • 当请求的路径是一个目录而不是具体的文件时,koa-static 会返回该目录下的文件列表。
  3. 缓存控制:

    • koa-static 可以设置静态文件的缓存头,如 Cache-ControlExpires 等,以提高页面加载速度。
    • 通过合理的缓存设置,可以减少重复请求静态资源的带宽和服务器负载。
  4. 文件压缩:

    • koa-static 可以对静态文件进行 gzip 压缩,减小传输数据的体积,提高网页加载速度。
    • 当客户端支持 gzip 压缩时,koa-static 会自动为响应添加 Content-Encoding: gzip 头部。

在根目录下创建一个static静态资源目录,结构如下所示:

├── static # 静态资源目录
│   ├── css/index.js
│   ├── image/demo.jpg
│   ├── js/index.js
│   └── index.html

入口文件index.js修改如下:

const Koa = require('koa')
const path = require('path')
const static = require('koa-static')

const app = new Koa()

// 静态资源目录对于相对入口文件index.js的路径
const staticPath = './static'

app.use(static(
  path.join( __dirname,  staticPath)
))

app.listen(3000, () => {
  console.log('[demo] static-use-middleware is starting at port 3000')
})

启动后,默认加载的是static目录下的index.html。在连接中更改路径localhost://3000/images/demo.jpg,回车后会直接读取并展示本地/static/image/demo.jpg图片。

7. cookie缓存

在 Koa 中,你可以使用 ctx.cookies 对象来获取和设置 cookies。

Koa 的 ctx.cookies 对象提供了以下常用的配置选项:

  • maxAge: cookie 的有效期,以毫秒为单位。
  • expires: cookie 的过期时间,是一个 Date 对象。
  • path: cookie 的路径,默认为 /
  • domain: cookie 的域名。
  • secure: 如果设置为 true,则只能通过 HTTPS 访问 cookie。
  • httpOnly: 如果设置为 true,则客户端无法通过 JavaScript 访问 cookie。
  • signed: 如果设置为 true,则 cookie 会被签名以防止篡改。
const Koa = require('koa')
const app = new Koa()

app.use( async ( ctx ) => {

  if ( ctx.url === '/index' ) {
    ctx.cookies.set(
      'cid', 
      'hello world',
      {
        domain: 'localhost',  // 写cookie所在的域名
        path: '/index',       // 写cookie所在的路径
        maxAge: 10 * 60 * 1000, // cookie有效时长
        expires: new Date('2024-09-15'),  // cookie失效时间
        httpOnly: false,  // 是否只用于http请求中获取
        overwrite: false  // 是否允许重写
      }
    )
    ctx.body = 'cookie is ok'
  } else {
    ctx.body = 'hello world' 
  }

})

app.listen(3000)

运行结果如下: image.png

8. 总结

通过以上基础入门的知识与实践,基本摸清了Koa中如何去加载和使用一些中间件。但是仅仅靠着这些基础知识是不够的,在后面学习中,将通过具体的案例介绍如何在Koa中使用模板引擎、实现简单的文件上传,以及如何使用Koa在node.js环境下对MySQL数据库进行建表,增、删、改、查等操作。