1.认识Koa
1.1 Koa是什么
Koa 是一个轻量级、灵活的 Node.js Web 应用框架。它是由 Express 原班人马开发的,旨在为 Web 应用程序和 API 提供一个更优雅、更富有表现力的基础。相比于 Express,Koa 的设计更加简单和优雅。它摒弃了一些 Express 中的复杂功能,专注于提供一个更简洁、更灵活的 Web 开发框架。许多开发者认为 Koa 是 Express 的继任者,它更适合构建复杂的、可扩展的 Web 应用程序和 API。
1.2 可以用Koa来做什么
以下是一些常见的使用场景:
- Web 应用程序:
- 使用 Koa 可以快速搭建出功能完备的 Web 应用程序,包括博客、电商网站、企业官网等。
- Koa 的中间件机制允许开发者根据需求灵活地集成各种功能,如身份验证、模板引擎、静态资源服务等。
- API 服务:
- Koa 非常适合构建 RESTful API 服务,可以轻松地处理 HTTP 请求、解析参数、生成 JSON 响应等。
- 借助 Koa 的异步处理能力,开发者可以构建高性能的 API 服务,满足各种复杂的业务需求。
- 微服务架构:
- 由于 Koa 的模块化和可扩展性,开发者可以将应用程序拆分成多个独立的微服务,提高系统的灵活性和可维护性。
- Koa 可以与其他微服务框架如 Micro 或 Moleculer.js 等配合使用,构建复杂的微服务架构。
- 实时应用程序:
- Koa 可以与 WebSocket 等实时通信技术相结合,开发实时聊天应用、协作编辑器、实时数据可视化等应用程序。
- 中间件开发:
- Koa 本身就是一个中间件框架,开发者可以开发自己的 Koa 中间件,并在自己的应用程序或其他 Koa 应用中使用。
- 社区中已经有许多优秀的 Koa 中间件可供选择和参考。
- 快速原型开发:
- 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服务,那如何热更新代码来帮助我们提高开发效率?
- 安装
nodemon
npm install nodemon
npm i nodemon -g // 建议直接全局安装
- 修改
package.js
"scripts": {
"start": "nodemon index.js"
}
运行npm run start再次启动服务,这时修改代码后只需要刷新浏览器即可,不用重启node服务了!
3. 中间件
Koa 中间件是 Koa.js 框架中一个非常核心的概念。Koa 中间件主要用于以下几个方面:
- 请求处理:Koa 中的中间件可以对 HTTP 请求进行处理,包括解析请求参数、设置响应头、发送响应等操作。
- 错误处理:中间件可以捕获并处理应用程序中抛出的异常,提供友好的错误响应。
- 日志记录:中间件可以记录请求的相关信息,如 HTTP 方法、URL、状态码等,方便日后排查问题。
- 跨域支持:中间件可以设置 CORS 相关的响应头,允许前端跨域访问后端接口。
- 访问控制:中间件可以实现基于角色或权限的访问控制逻辑。
- 数据缓存:中间件可以对某些数据进行缓存,提高响应速度。
- 内容压缩:中间件可以对响应内容进行 Gzip 压缩,减小传输数据量。
- 请求校验:中间件可以对请求参数进行校验,确保输入的合法性。
- 认证授权:中间件可以实现用户的认证和授权功能。
- 其他功能:中间件可以根据实际需求提供各种其他功能,如服务监控、性能优化等。
Koa 中间件通过 app.use() 方法进行挂载。每个中间件函数接收 ctx 和 next 两个参数,ctx 代表当前请求的上下文对象,next 则用于调用下一个中间件。中间件的执行顺序遵循"洋葱模型",即先进后出。来看下洋葱模型的图:
关于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.html和404.html。index.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')
})
点击后跳转到对应的html页面。
理解下app.use(router.routes()) 和 app.use(router.allowedMethods()) 这两行代码,在使用 Koa-router 时它们非常重要,作用如下:
-
app.use(router.routes()):- 这行代码将路由中间件挂载到 Koa 应用程序上。
- 它告诉 Koa 应用程序使用 Koa-router 定义的路由规则来处理请求。
- 当客户端发起请求时,Koa 应用程序会根据这些路由规则进行匹配和分发。
-
app.use(router.allowedMethods()):- 这行代码是对上一行的补充。
- 它为每个路由添加了 HTTP 方法校验,确保请求方法与路由定义的方法匹配。
- 如果请求方法不匹配,它会自动返回
405 Method Not Allowed的 HTTP 状态码。 - 这有助于确保应用程序的健壮性和安全性。
5. 数据请求
5.1 GET请求数据获取
对于 GET 请求,使用 ctx.query 或 ctx.request.query 是最简单和常见的方式。
-
通过
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}`;
});
-
通过
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')
})
补充: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 有以下几个主要功能:
-
静态文件服务:
koa-static可以为你的 Koa 应用提供静态文件服务,如 HTML、CSS、JavaScript、图片等。- 当客户端请求某个静态资源时,
koa-static会自动从指定的目录中查找并返回对应的文件内容。
-
目录浏览:
koa-static可以自动生成目录浏览页面,方便用户查看指定目录下的文件列表。- 当请求的路径是一个目录而不是具体的文件时,
koa-static会返回该目录下的文件列表。
-
缓存控制:
koa-static可以设置静态文件的缓存头,如Cache-Control、Expires等,以提高页面加载速度。- 通过合理的缓存设置,可以减少重复请求静态资源的带宽和服务器负载。
-
文件压缩:
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)
运行结果如下:
8. 总结
通过以上基础入门的知识与实践,基本摸清了Koa中如何去加载和使用一些中间件。但是仅仅靠着这些基础知识是不够的,在后面学习中,将通过具体的案例介绍如何在Koa中使用模板引擎、实现简单的文件上传,以及如何使用Koa在node.js环境下对MySQL数据库进行建表,增、删、改、查等操作。