(1)简介
基于Node.js平台的web开发框架
由Express原班人马打造
环境依赖Node v7.6.0及以上
Koa2特点
●支持async\await
●洋葱模型的中间件
(2)步骤
●检查Node的环境
node -V
●安装Koa
npm init -y
npm install koa
●创建并编写app.js文件
1.创建Koa对象
2.编写响应函数(中间件)
3.监听端口
●启动服务器
node app.js
- const Koa=require('koa')
- const app=new Koa()
- // 编写响应函数(中间件)
- // ctx:上下文,web容器,ctx.request ctx.response
- // next: 下一个中间件,下一层中间件是否能够得到执行, 取决于next这个函数有没有被调用
-
- app.use((ctx,next)=>{
- console.log(ctx.request.url)
- //设置响应体
- ctx.response.body='hello world'
- })
- app.listen(3000)
(3)中间件特点
●Koa对象通过use方法加入- 个中间件
●一个中间件就是一个函数
●中间件的执行顺序符合洋葱模型
●内层中间件能否执行取决于外层中间件的next函数是否被调用
●调用next函数得到的是Promise对象
- app.use(async(ctx,next)=>{
- //刚进入中间件想做到事情
- await next()
- //内层所有中间件结束后想做的事情
- })
后台项目的目标:
●1.计算服务器处理请求的总耗时
●2.在响应头.上加上响应内容的mime类型
●3.根据URL读取指定目录下的文件内容
后台项目的实现步骤:
●1.项目准备
●2.总耗时中间件
●3.响应头中间件
●4.业务逻辑中间件
●5.允许跨域
=========================================================================(1)项目准备
●1.安装包
npm init -y
npm install koa
●2.创建文件和目录结构
app.js
data/
middleware/
koa_ response_ data.js(处理业务逻辑的中间件,读取某个json文件的数据)
koa_ response_ _duration.js(计算服务器消耗时长的中间件)
koa_ response_ header.js(设置响应头的中间件)
utils/
file_ utils.js(读取文件的工具方法)
(2).总耗时中间件
●1.第1层中间件
●2.计算执行时间
一进入时记录开始时间,其他所有中间件执行完后记录结束时间,两者相减
●3.设置响应头
X-Response-Time:5ms
-
- // 计算服务器消耗时长的中间件
- 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')
- }
(3)响应头中间件
●1.第2层中间件
●2.获 取mime类型
application/json
●3.设置响应头
Content-Type:application/json; charset=UTF-8
- async (ctx, next) => {
- const contentType = 'application/json; charset=utf-8'
- ctx.set('Content-Type', contentType)
- await next()
- }
(4)业务逻辑中间件
●1.第3层中间件
●2.读取文件内容
获取请求的路径,拼接文件路径
读取该路径对应文件的内容
●3.设置响应体
ctx.response.body
- const path = require('path')
- const fileUtils = require('../utils/file_utils')
- module.exports = async (ctx, next) => {
- // 根据url
- const url = ctx.request.url // /api/seller ../data/seller.json
- let filePath = url.replace('/api', '') // /seller
- filePath = '../data' + filePath + '.json' // ../data/seller.json
- filePath = path.join(__dirname, filePath)
- try {
- const ret = await fileUtils.getFileJsonData(filePath)
- ctx.response.body = ret
- } catch (error) {
- const errorMsg = {
- message: '读取文件内容失败, 文件资源不存在',
- status: 404
- }
- ctx.response.body = JSON.stringify(errorMsg)
- }
-
- console.log(filePath)
- await next()
- }
- /utils下的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)
- }
- })
- })
- }
(5)跨域配置
1.实际是通过Ajax访问服务器
2.同源策略
同协议\同域名\同端口
当前页面的地址和Ajax获取数据的地址
3.设置响应头
- async(ctx,next)=>{
-
- ctx.set("Access-Control-Allow-Origin", "*")
- ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE")
- await next()
- }
●安装Websocket包
npm i ws -S
●创建WebSocket实例对象
- const WebSocket = require("ws ")
- //创建出WebSocket实例对象
- const wss= new WebSocket. Server({
- port: 9998
- })
●监听事件
- wss.on("connection",client => {
- console.log("有客户端连接...")
- client. on ("message", msg => {
- console.log("客户端发送数据过来了")
- // 发送数据给客户 端
- client.send('hello socket ')
- })
- })
测试代码如下:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Document</title>
- </head>
- <body>
- <button id="connect">连接</button>
- <button id="send" disabled="true">发送数据</button> <br>
- 从服务器接收的数据如下:<br>
- <span id="content"></span>
- <script>
- var connect = document.querySelector('#connect')
- var send = document.querySelector('#send')
- var content = document.querySelector('#content')
- var ws = null
- connect.onclick = function() {
- ws = new WebSocket('ws://localhost:9998')
- ws.onopen = () => {
- console.log('连接服务器成功')
- send.disabled = false
- }
- ws.onmessage = msg => {
- console.log('从服务器接收到了数据')
- content.innerHTML = msg.data
- }
- ws.onclose = e => {
- console.log('服务器关闭了连接')
- send.disabled = true
- }
- }
- send.onclick = function(){
- ws.send('hello websocket from frontend')
- }
- </script>
- </body>
- </html>
-
●1.创建service\web_ socket_ service.js文件
- const WebSocket = require("ws")
- // 创建出WebSocket实例对象
- const wss = new WebSocket.Server({
- port: 9998
- })
- module.exports.listen = function() {
- wss.on("connection", ws => {
- console.log("有客户端连接...")
- ws.on("message", msg => {
- console.log("客户端发送数据过来了")
- })
- })
- }
-
●2.在app.js中引入web_ socket_ service.js 这个文件,并调用listen方法
- const webSocketService = require('./service/web_ socket_ _service')
- webSocketService.listen()
●3.约定好和客户端之 间数据交互的格式和含义
客户端和服务端之间的数据交互采用JSON格式
客户端发送数据给服务端的字段如下:
- {
- "action": "getData",
- "socketType": "trendData",
- "chartName": "trend",
- "value": ""
- }
或者
- {
- "action": "fullScreen",
- "socketType": "fullScreen" ,
- "chartName": "trend",
- "value": true
- }
-
-
或者
- {
- ! action": "themeChange
- "socketType": "themeChange" ,
- "chartName": ""
- "value": "chalk"
- }
其中:
action:代表某项行为,可选值有
■getData 代表获取图表数据
■fullscreen代表产生了全屏事件
■themeChange 代表产生了主题切换的事件
■socketType:代表业务模块类型,这个值代表前端注册数据回调函数的标识,可选值有
■trendData
■sellerData
■ mapData
■rankData
■hotData
■ stockData
■ fullscreen
■themeChange
■chartName :代表图表名称,如果是主题切换事件,可不传此值,可选值有:
■ trend
■seller
■map
■ rank
■hot
■stock
■value:代表具体的数据值,在获取图表数据时,可不传此值,可选值有
■如果是全屏事件, true代表全屏, false代表非全屏
■如果是主题切换事件,可选值有chalk或者vintage
服务端发送给客户端的数据如下,
- {
- "action": "getData",
- "socketType": "trendData",
- "chartName": "trend",
- "value": "",
- "data": "从文件读取出来的json文件的内容"
- }
- 或者
- {
- "action": "fullScreen",
- "socketType": "fullScreen",
- "chartName": "trend",
- "value": true
- }
- 或者
- {
- "action": "themeChange",
- "socketType": "themeChange",
- "chartName": "",
- "value": "chalk"
- }
注意,除了action为getData时,服务器会在客户端发过来数据的基础之上,增加data字段, 其他的情况,服务器会原封不动的将从某一个客户端发过来的数据转发给每一 个处于连接状态
的客户端
●4代码实现
- const path = require('path')
- const fileUtils = require('../utils/file_utils')
- const WebSocket = require("ws")
- // 创建出WebSocket实例对象
- const wss = new WebSocket.Server({
- port: 9998
- })
- module.exports.listen = function() {
- wss.on("connection", client => {
- console.log("有客户端连接...")
- client.on("message", async msg => {
- let payload = JSON.parse(msg)
- if (payload.action === 'getData') {
- // 返回每个模块的数据
- let filePath = '../data/' + payload.chartName + '.json' //
- ../data/seller.json
- filePath = path.join(__dirname, filePath)
- const ret = await fileUtils.getFileJsonData(filePath)
- payload.data = ret // 增加data字段
- client.send(JSON.stringify(payload))
- } else {
- // 主题切换, 全屏切换, 进行每个客户端的同步, 收到什么数据就发送什么数据
- wss.clients.forEach(client => {
- console.log("*****************************************")
- client.send(message)
- })
- }
- })
- })
- }