node.js的下一代web框架 -- Koa

本系列为各个前端相关知识重新深度学习,有需要的小伙伴可关注该专栏,后续会持续更新不同类型的前端相关知识总结

前言

Koa 是由 Express 背后的团队设计的一个新的 Web 框架,能够帮助你使用nodejs很方便地构建服务端应用程序。本文将详细介绍koa的使用,以及如何构建一个Koa开发脚手架,欢迎点赞收藏!

认识Koa

koa实际上可以说是express的升级版本,Koa 需要 node v12 或更高版本才能支持 ES2015 和异步函数。

先通过一个简单的demo,来了解它是如何运行的。

(1)安装koa

csharp 复制代码
//初始化
pnpm init 
//安装koa
pnpm install koa 

(2)开启服务,并返回结果

ini 复制代码
const Koa = require('koa');
const app = new Koa();

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

app.listen(3000); 

(3)运行程序node demo.js

通过上面简单的几个步骤,一个hello world 的Koa服务就已经运行成功了,那么怎么验证呢,我们打开浏览器,访问http://localhost:3000/,可以看到如下内容,页面上输出了Hello Koa

app对象

从上面的demo我们可以看出,Koa 应用程序其实就是一个包含一组中间件函数的对象,它按照类似堆栈的方式组织和执行。

级联

可以通过使用await next();来实现简单的中间件行为。可以看以下示例:

ini 复制代码
const Koa = require("koa");
const app = new Koa();


app.use(async (ctx, next) => {
  await next();
console.log('中间件1')
});

app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
console.log('中间件2')
});

// response
app.use(async (ctx) => {
  ctx.body = "Hello World";
});

app.listen(3000);

上面示例中,当请求开始时首先请求流通过中间件1和中间件2,然后继续移交控制给 response 中间件。当一个中间件调用 next() 则该函数暂停并将控制传递给定义的下一个中间件。当在下游没有更多的中间件执行后,堆栈将展开并且每个中间件恢复执行其上游行为。上面demo运行结果如下:

属性

(1)app.listen() 将Koa 应用程序被绑定到对应的端口,它其实是以下方法的语法糖:

ini 复制代码
const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);

(2)app.callback() 返回适用于 http.createServer() 方法的回调函数来处理请求。你也可以使用此回调函数将 koa 应用程序挂载到 Connect/Express 应用程序中。 (3)app.use(function) 将给定的中间件方法添加到此应用程序。app.use() 返回 this, 因此可以链式表达.

scss 复制代码
app.use(someMiddleware)
app.use(someOtherMiddleware)
app.listen(3000)
//它等同于
app.use(someMiddleware)
  .use(someOtherMiddleware)
  .listen(3000)

(4)app.keys 设置签名的 Cookie 密钥。

(5)app.context app.context 是从其创建 ctx 的原型。您可以通过编辑 app.context 为 ctx 添加其他属性。这对于将 ctx 添加到整个应用程序中使用的属性或方法非常有用,这可能会更加有效(不需要中间件)和/或 更简单(更少的 require()),而更多地依赖于ctx,这可以被认为是一种反模式。 例如,要从 ctx 添加对数据库的引用:

ini 复制代码
app.context.db = db();
app.use(async ctx => {
  console.log(ctx.db);
});

错误处理

可以添加一个 "error" 事件侦听器,如果 req/res 期间出现错误,并且 无法 响应客户端,Context实例仍然被传递:

javascript 复制代码
app.on('error', (err, ctx) => {
  log.error('server error', err, ctx)
});

Context上下文

Koa的Context封装了node和koa的request对象和response对象,每个请求都将创建一个Context,并在中间件中作为接收器引用,或者ctx标识符,如以下代码片段所示:

ini 复制代码
app.use(async ctx => {
  ctx; // 这是 Context
  ctx.request; // 这是 koa Request
  ctx.response; // 这是 koa Response
});

API

(1)ctx.req - Node 的 request 对象.

(2)ctx.res - Node 的 response 对象. (3)ctx.request - koa 的 Request 对象. (4)ctx.response - koa 的 Response 对象. (5)ctx.state - 推荐的命名空间,用于通过中间件传递信息和你的前端视图。

ini 复制代码
ctx.state.user = await User.find(id);

(6)ctx.app - 应用程序实例引用 (7)ctx.cookies.get(name, [options]) (8)ctx.cookies.set(name, value, [options]) options配置:

vbnet 复制代码
通过 options 设置 cookie name 的 value :
maxAge: 一个数字, 表示从 Date.now() 得到的毫秒数.
expires: 一个 Date 对象, 表示 cookie 的到期日期 (默认情况下在会话结束时过期).
path: 一个字符串, 表示 cookie 的路径 (默认是/).
domain: 一个字符串, 指示 cookie 的域 (无默认值).
secure: 一个布尔值, 表示 cookie 是否仅通过 HTTPS 发送 (HTTP 下默认为 false, HTTPS 下默认为 true). 阅读有关此参数的更多信息.
httpOnly: 一个布尔值, 表示 cookie 是否仅通过 HTTP(S) 发送,, 且不提供给客户端 JavaScript (默认为 true).
sameSite: 一个布尔值或字符串, 表示该 cookie 是否为 "相同站点" cookie (默认为 false). 可以设置为 'strict', 'lax', 'none', 或 true (映射为 'strict').
signed: 一个布尔值, 表示是否要对 cookie 进行签名 (默认为 false). 如果为 true, 则还会发送另一个后缀为 .sig 的同名 cookie, 使用一个 27-byte url-safe base64 SHA1 值来表示针对第一个 Keygrip 键的 cookie-name=cookie-value 的哈希值. 此签名密钥用于检测下次接收 cookie 时的篡改.
overwrite: 一个布尔值, 表示是否覆盖以前设置的同名的 cookie (默认是 false). 如果是 true, 在同一个请求中设置相同名称的所有 Cookie(无论路径或域)是否在设置此Cookie 时从 Set-Cookie 消息头中过滤掉.

(9)ctx.throw([status], [msg], [properties]) - 用来抛出一个包含 .status 属性错误的帮助方法,其默认值为 500。这样 Koa 就可以做出适当地响应。

sql 复制代码
ctx.throw(400, 'name required', { user: user });

(10)ctx.respond - 为了绕过 Koa 的内置 response 处理,你可以显式设置 ctx.respond = false;。 如果您想要写入原始的 res 对象而不是让 Koa 处理你的 response,请使用此参数

request别名

所谓request别名就是在使用上可以省略request,如下所示输出内容:

ini 复制代码
const Koa = require("koa");
const app = new Koa();
// response
app.use(async (ctx) => {
  ctx.body = "Hello World";
 console.log(ctx.header,ctx.request.header)
});
app.listen(3000);

可以看出ctx.header,ctx.request.header输出的内容是一致的,可用的别名已经每个属性的用法如下:

scss 复制代码
ctx.header //请求头对象。request.header=设置请求头对象。
ctx.headers //请求头对象。别名为 request.header. request.headers= 设置请求头对象。别名为 request.header=.
ctx.method //请求方法。
ctx.method= //设置请求方法,对于实现诸如 methodOverride() 的中间件是有用的。
ctx.url //获取请求 URL.
ctx.url= //设置请求 URL, 对 url 重写有用。
ctx.originalUrl //获取请求原始URL。
ctx.origin //获取URL的来源,包括 protocol 和 host。
ctx.href //获取完整的请求URL,包括 protocol,host 和 url。
ctx.path //获取请求路径名。
ctx.path= //设置请求路径名,并在存在时保留查询字符串。
ctx.query //获取解析的查询字符串, 当没有查询字符串时,返回一个空对象。
ctx.query= //将查询字符串设置为给定对象
ctx.querystring //设置原始查询字符串。
ctx.querystring= //设置原始查询字符串。
ctx.host //存在时获取主机(hostname:port)。当 app.proxy 是 true 时支持 X-Forwarded-Host,否则使用 Host。
ctx.hostname //存在时获取主机名。当 app.proxy 是 true 时支持 X-Forwarded-Host,否则使用 Host。
ctx.fresh //检查请求缓存是否"新鲜",也就是内容没有改变。
ctx.stale //与 request.fresh 相反.
ctx.socket //返回请求套接字
ctx.protocol //返回请求协议,"https" 或 "http"。
ctx.secure //通过 ctx.protocol == "https" 来检查请求是否通过 TLS 发出
ctx.ip //请求远程地址。 当 app.proxy 是 true 时支持 X-Forwarded-Proto。
ctx.ips //当 X-Forwarded-For 存在并且 app.proxy 被启用时,这些 ips 的数组被返回,从上游 - >下游排序。 禁用时返回一个空数组。
ctx.subdomains //以数组形式返回子域。
ctx.is() //检查传入请求是否包含 Content-Type 消息头字段
ctx.accepts() //检查给定的 type(s) 是否可以接受,如果 true,返回最佳匹配,否则为 false
ctx.acceptsEncodings() //检查 encodings 是否可以接受,返回最佳匹配为 true,否则为 false。 请注意,您应该将identity 作为编码之一
ctx.acceptsCharsets() //检查 charsets 是否可以接受,在 true 时返回最佳匹配,否则为 false。
ctx.acceptsLanguages() //检查 langs 是否可以接受,如果为 true,返回最佳匹配,否则为 false。
ctx.get() //返回请求头(header), field 不区分大小写.

Response 别名

可用的response别名以及属性如下:

scss 复制代码
ctx.body //获取响应主体。
ctx.body= //将响应体设置为以下之一:string 写入、Buffer 写入、Stream 管道、Object || Array JSON-字符串化、null 无内容响应。如果 response.status 未被设置, Koa 将会自动设置状态为 200 或 204。
ctx.status //获取响应状态
ctx.status= //通过数字代码设置响应状态
ctx.message //获取响应的状态消息. 默认情况下, response.message 与 response.status 关联.
ctx.message= //将响应的状态消息设置为给定值
ctx.length= //将响应的 Content-Length 设置为给定值。
ctx.length //以数字返回响应的 Content-Length
ctx.type= //设置响应 Content-Type 通过 mime 字符串或文件扩展名
ctx.type //获取响应 Content-Type, 不含 "charset" 等参数。
ctx.headerSent //检查是否已经发送了一个响应头。 用于查看客户端是否可能会收到错误通知
ctx.redirect() //执行 [302] 重定向到 url.
ctx.attachment() //将 Content-Disposition 设置为 "附件" 以指示客户端提示下载
ctx.set() //用一个对象设置多个响应头fields:
ctx.append() //附加额外的消息头 
ctx.remove() //删除消息头
ctx.lastModified=
ctx.etag=

开发脚手架搭建

生成package.json

通过pnpm生成package.json

csharp 复制代码
pnpm init

安装依赖

java 复制代码
// koa相关依赖
npm i koa koa-bodyparser koa-router koa-session koa-static koa2-cors 
// 依赖注解
npm i --save-dev @types/koa @types/koa-bodyparser @types/koa-router @types/koa-session @types/koa-static @types/koa2-cors

初始化tsc文件

csharp 复制代码
//生成tsconfig.json
tsc --init

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2015", // 目标语言版本
    "module": "commonjs", // 指定生成代码的模板标准
    "rootDir": "./", // 指定输出目录, 默认是dist文件夹
    "strict": true, // 严格模式
    "allowSyntheticDefaultImports": true, // 没有默认导出时, 编译器会创建一个默认导出
    "esModuleInterop": true, // 允许export= 导出, 由import from导入
    "forceConsistentCasingInFileNames": true, // 强制区分大小写
    "outDir": "./dist/"
  },
  "include": [
    // 需要编译的的文件和目录
    "src/**/*"
  ],
  "files": [
    "src/app.ts"
  ],
}

新建入口文件app.ts

javascript 复制代码
// src/app.ts

// 引入koa
import Koa from 'koa'
import http from 'http'
// 创建koa实例
const app = new Koa()
// 中间件
app.use(async (ctx) => {
  ctx.body = 'Hello World'
})
// 监听端口
app.listen(3000, () => {
  console.log('app started at port 3000...')
})

修改package.json

json 复制代码
"scripts": {
    "dev": "cross-env NODE_ENV=development nodemon ./src/app.ts",
    "pm2": "pm2 start ./src/app.js",
    "build": "tsc && cp Dockerfile ./dist && cp docker-compose.yml ./dist && cp package.json ./dist",
    "runtime": "pm2-runtime start src/app.js"
},

这样就可以使用pnpm run dev 来启动项目了。

总结

本文整体概述了koa相关API和使用,脚手架搭建还有所欠缺,后续有进展会继续更新,有需要的可以点个关注。

相关推荐
f8979070701 小时前
layui动态表格出现 横竖间隔线
前端·javascript·layui
鱼跃鹰飞1 小时前
Leecode热题100-295.数据流中的中位数
java·服务器·开发语言·前端·算法·leetcode·面试
二十雨辰1 小时前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
霸王蟹2 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
小白求学12 小时前
CSS计数器
前端·css
Anita_Sun2 小时前
🌈 Git 全攻略 - Git 的初始设置 ✨
前端
lucifer3113 小时前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
等什么君!3 小时前
复习HTML(进阶)
前端·html
儒雅的烤地瓜3 小时前
JS | 如何解决ajax无法后退的问题?
前端·javascript·ajax·pushstate·popstate事件·replacestate
觉醒法师3 小时前
Vue3+TS项目 - ref和useTemplateRef获取组件实例
开发语言·前端·javascript