第一部分:前端如何实现即时通讯?websocket
基于Web的前端,存在以下几种可实现即时通讯的方式:
-
短轮询 (开个定时器,每隔一段时间发送请求:实时性不强)
-
Comet-ajax (发送一个请求,服务器只要数据不更新,就一直阻塞:服务器压力过大)
-
SSE(利用了http协议,流数据的传输,并不是养个意义上的双向通讯,无法复用连接)
-
WebSocket(性能和效率都高)
短轮询
短轮询就是客户端定时发送请求,获取服务器上的最新数据。不是真正的即时通讯,但一定程度上可以模拟即时通讯的效果。
优缺点:
-
优点:浏览器兼容性好,实现简单
-
缺点:实时性不高,资源消耗高,存在较多无用请求,影响性能
WebSocket
需要下载三方包
npm i ws
服务器端部分
// 以下为webSocket
const http = require('http')
const server = http.createServer();
const WebSocket = require('ws')
const wss = new WebSocket.Server({server})
server.listen(9998)
// 对客户端的连接事件进行监听
// client:代表的是客户端的连接socket对象
wss.on('connection',client=>{
console.log('有客户端连接成功了。。。')
// 对客户端的连接对象进行message事件监听
// msg:由客户端发给服务端的数据
client.on('message',msg=>{
console.log('客户端发送数据给服务端了:'+msg)
// msg为16进制,使用msg.toString()转为字符串
// 由服务端往客户端发送数据
client.send(msg.toString()) //必须要传入字符串
})
})
浏览器端部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
输入内容:<input type="text"><hr/>
<button id="box1">给服务器发送内容</button>
</body>
<script>
const ws = new WebSocket('ws://localhost:9998')
// 连接成功事件
ws.onopen=()=>{
console.log('连接服务器成功了。。。')
}
ws.onclose=()=>{
console.log('连接服务器失败了')
}
ws.onmessage=(msg)=>{
console.log(msg)
console.log(Object.prototype.toString.call(msg.data))
console.log('接收到从服务器发送过来的数据了',msg.data)
}
document.querySelector('#box1').addEventListener('click',()=>{
// 给服务器发送数据ws.send()
ws.send(document.querySelector('input').value)
})
</script>
</html>
第二部分:一次完整的HTTP请求过程
// 1.输入www.baidu.com 回车后,需要先进行DNS解析,得到公网ip
// 2.根据ip地址找到服务器,开始建立TCP连接,三次握手
// 3.浏览器端发送请求,服务器端进行响应 index.html
// 4.浏览器解析 index.html,加载index.html 中需要加载的其他一些资源(css,js,图片)
// 5.浏览器完成页面的解析渲染
// 6.http服务完成,释放关闭TCP连接,四次挥手
第二部分之三次握手
这和礼貌的好友道别一样:(a:客户端,b:服务器)
1、一开始A想要回家离开,但是呢?怕b还有事情要交代,那么呢?只好先向b打招呼,我要走了,请求停止交谈(此时,a到b的链接没有断开,依旧可以进行通信)
2、同意a的请求,说好的,但是我这里可能还有一些话(数据)没说完。我检查看看,你等等,等我说完你再走。
3、b确实没啥要补充的了,就告诉我可以散伙了
4、a说好的,知道了,88,(b得知a走开了,关闭了自己的链接)
第四部分之四次挥手
(1)一方a发起断开连接的消息
(2)另一方b会确认收到断开的需求,但是会要求等一等,确定是否数据传输完毕(3)b
(3)b当确认完之后,确实数据都传完了,告知a,连接可以断开了
(4)a确认完之后,确实数据都传完了,告知a,连接可以断开
第三部分:Koa2
Koa2特点
支持async、await
洋葱模型中间件
Koa2快熟上手
第一步:检查Node的环境
node-v
第二步:安装Koa
npm init -y
npm install koa
第三步:创建并编写app.js文件
1.创建Koa对象
2.编写响应中间件
3.监听端口
第四步:启动服务器
node app.js
具体实施过程如下
在app.js中
// 1.创建Koa对象
const Koa = require('koa')
const app = new Koa()
// 绑定第一层中间件
const respDurationMiddleware = require('./middleware/koa_response_duration')
app.use(respDurationMiddleware)
// // 第二层中间件
const respHeaderMiddleware =require('./middleware/koa_response_header')
app.use(respHeaderMiddleware)
// // 第三层中间件
const respDadaMiddleware = require('./middleware/koa_response_data')
app.use(respDadaMiddleware)
// 3.绑定端口号
app.listen(3000,'192.168.87.206',()=>{
console.log('启动了服务器')
})
在第二层中间件的文件夹中设置
const respHeaderMiddleware =require('./middleware/koa_response_header')
// 设置响应头的中间件
module.exports=async(ctx,next)=>{
const contentType ="application/json;charset=utf-8"
ctx.set('content-type',contentType)
// 如下为响应头跨域
ctx.set('Access-Control-Allow-Methods','OPTIONS,GET,PUT,POST,DELETE')
ctx.set('Access-Control-Allow-Origin',"*")
// 响应体
// ctx.response.body="{'success':true}"
await next()
}
在第一层的中间件中设置
const respDurationMiddleware = require('./middleware/koa_response_duration')
// 计算服务器消耗时长的中间件
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')
}
在第三层的中间件中设置
const respDadaMiddleware = require('./middleware/koa_response_data')
// 处理业务逻辑的中间件,读取某一个json文件响应给服务器
// 1.获取请求的路径,拼接文件路径
// 2.读取该路径对应文件的内容
const fs = require("fs")
const path=require('path')
module.exports= async(ctx,next)=>{
console.log('第三层中间件')
// 根据url
const url = ctx.request.url
// 获取绝对路径
let filePath = url.replace('/api','')
filePath ='/data'+filePath+'.json'
// 生成绝对路径
try {
const conmon = fs.readFileSync(path.join(__dirname,'..',filePath),'utf-8')
ctx.response.body=conmon.toString()
} catch (error) {
const errorMsg={
"message":"读取文件内容失败,文件资源不存在",
"status":"404",
}
ctx.response.body=JSON.stringify(errorMsg)
}
await next()
}