此项目后台采用 Koa2 进行开发配置,相关配置整理如下。
1. Koa2 概述
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。
关于 Express、Koa、Koa2 的区别见下表:
框架 | 作用 | 异步处理 |
---|---|---|
Express | web 框架 | 回调函数 |
Koa | web 框架 | Generator + yield |
Koa2 | web 框架 | async / await |
async / await 在 node 7.6 版本后才支持使用,因此 Koa2 环境要求 Node v7.6.0 及以上。
2. Koa2 快速上手
> 基本步骤
- 检查 Node 环境( > 7.6 )
node -v
- 安装 Koa
npm init -y
npm install koa
- 创建并编写 app.js 文件
a. 创建 Koa 对象
b. 编写响应函数(中间件)
c. 监听端口
- 启动服务器
node app.js
具体而言,实现代码如下:
const Koa = require('koa')
// 1. 创建 koa 对象
const app = new Koa()
// 2. 编写响应函数(中间件)
app.use((ctx, next) => {
console.log(ctx.request.url);
ctx.response.body = 'hello world'
})
// 3. 绑定端口号 3000
app.listen(3000)
> 中间件的特点
Koa 对象通过 use 的方式加入中间件,一个中间件就是一个函数,中间件的执行顺序符合洋葱模型。
app.use(async(ctx, next) => {
// 刚进入中间件要做的事情
await next();
// 内层所有中间件结束之后想做的事情
})
如上代码即为一个中间件,其中 ctx 表示上下文,主要指 web 容器,可以通过 ctx.request
和 ctx.response
分别获取请求对象和响应对象。而该代码中的 next 指代下一个中间件。内层中间件能否执行取决于外层中间件的 next 函数是否调用。
此外,需注意调用 next 函数得到的是 Promise 对象。
3. 后台项目
> 后台项目的目标
- 计算服务器处理请求的总耗时
- 在响应头中增加响应内容的 mime 类型
- 根据 URL 读取指定目录下的文件内容
> 后台项目的实现步骤
- 项目准备
- 总耗时中间件
- 响应头中间件
- 业务逻辑中间件
- 允许跨域
> 项目的准备
- 安装包
npm init -y
npm install koa
- 创建文件和目录结构
相关文件目录说明:
文件(夹) | 说明 |
---|---|
app.js | 服务器入口文件 |
data | 存放前端图表所需的 json 文件数据 |
middleware | 存放中间件(业务逻辑、总耗时、设置响应头) |
utils | 工具方法(读取文件的工具方法) |
4. 总耗时中间件
此中间件位于第一层,计算中间时间为开始和结束时相减,通过响应头方式设置给前端浏览器。
> koa_resonse_dutation.js
// 计算服务器消耗时长的中间件
module.exports = async (ctx, next) => {
// 记录开始事件
const start = Date.now()
// 让内层中间件得到执行
await next()
// 记录结束的时间
const end = Date.now()
// 设置响应头 X-Response-Time
const duration = end - start
// ctx.set 设置响应头
ctx.set('X-Response-Time', duration + 'ms')
}
5. 响应头中间件
> koa_response_header.js
// 设置响应头的中间件
module.exports = async (ctx, next) => {
const contentType = 'application/json; charset=utf-8'
ctx.set('Content-Type', contentType)
await next()
}
6. 业务逻辑中间件
此中间件专门用于读取文件的内容。因为我们所要获取的是 json 文件,因此需要获取请求路径,拼接文件路径,才可正确读取文件内容。最后,将读取的文件内容设置到响应体中即可。
> koa_response_data.js
// 处理业务逻辑的中间件:读取某个 json 文件数据,响应给前端浏览器
const path = require('path')
const fileUtils = require('../utils/file_utils.js')
module.exports = async (ctx, next) => {
// 根据 url 读取文件
const url = ctx.request.url
// /api.seller ../data/seller.json
let filePath = url.replace('/api', '')
filePath = '../data' + filePath + '.json'
filePath = path.join(__dirname, filePath)
// 利用工具方法获取指定路径的数据
const ret = fileUtils.getFileJsonData(filePath)
ctx.response.body = ret
console.log(filePath);
await next()
}
> file_utils.js
// 读取文件的工具方法(用于读取某个路径下的文件内容)
const fs = require('fs')
module.exports.getFileJsonData = (filePath) => {
// 根据文件路径,读取文件内容
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (error, data) => {
if (error) {
// 读取文件失败
reject(error)
} else {
// 读取文件成功
resolve(data)
}
})
})
}
> 接口总览
目标 | 接口 |
---|---|
商家销量 | /api/seller |
预算开销 | /api/budget |
库存信息 | /api/stock |
销量趋势 | /api/trend |
销量排行 | /api/rank |
商家分布 | /api/map |
热销商品 | /api/hotproduct |
7. 允许跨域
通过 Ajax 访问服务器时,应遵循同源策略(同协议、同域名、同端口)。为了使跨域请求可以实现,需要对响应头进行设置。
> koa_response_header.js
// 设置响应头的中间件
module.exports = async (ctx, next) => {
const contentType = 'application/json; charset=utf-8'
ctx.set('Content-Type', contentType)
// 允许跨域
ctx.set('Access-Control-Allow-Origin', '*')
ctx.set('Access-Control-Allow-Methods', 'OPTIONS, GET, PUT, POST, DELETE')
await next()
}