网络杂记:Fetch、SSE、sendBeacon、websocket

495 阅读4分钟

引言

最近捏麻麻的乱吃外卖给吃中毒了,这几天在回血的同时看了哈小满哥的网络杂记还是十分棒的。欲将轻骑逐;大雪满刀弓。

任务安排

  • fetch

  • SSE

  • sendBeacon

  • WebSocket

一:fetch

1.基本使用

fetch(url,{
    method:'get/post',
    headers:{//请求头格式
      'Content-Type':'application/json'
    }
})

2.get请求

前端

fetch('http://localhost:3000/test1').then(res=>{
  return res.json()//将响应体数据解析成json
}).then(data=>{
  console.log(data)
})

后端:koa2

router.get('/test1', async (ctx, next) => {
  ctx.set("Content-Type",'application/json')
  ctx.body = {
    "name":"dzp"
  }
})

3.post请求

前端

    fetch('http://localhost:3000/test2',{
      headers:{
        'Content-Type':'application/json'
      },
      method:'post',
      body:JSON.stringify({
        name:'zhangsan',
        age:18
      })
    }).then(res=>{
      return res.json()
    }).then(data=>{
      console.log(data)
    })
    

后端:koa2

router.post('/test2', async (ctx, next) => {
  ctx.set("Content-Type",'application/json')
  ctx.body = {
    "name":"dzp"
  }
})   

4.取消请求

axios,fetch的取消请求已经趋于统一了,都是借助AbortController对象完成。

  1. 创建AbortController实例对象

  2. 请求体中添加signal属性

  3. 中断请求时调用abort()

     <body>
         <div onclick="stopAsync()">click</div>
         <script>
             let control = new AbortController()//步骤1
             fetch('http://localhost:3000/test3',{
               headers:{
                 'Content-Type':'application/json'
               },
               method:'post',
               body:JSON.stringify({
                 name:'zhangsan',
                 age:18
               }),
               signal:control.signal//步骤2
             }).then(res=>{
               return res.json()
             }).then(data=>{
               console.log(data)
             })
             
             //取消按钮点击
             function stopAsync() {
              control.abort()//步骤3
             }
         </script>
     </body>
     
    

5.携带cookie

fetch在发起http请求时cookie无法自动携带,而axios是自动携带的。通过添加credentials:'include'可以自动携带cookie

fetch('http://localhost:3000/test3',{
  credentials:'include',
}).then(res=>{
  return res.json()
}).then(data=>{
  console.log(data)
})

二:SSE

SSE(Server-Sent Events)指服务端向客户端主动发送消息的技术,它基于http长连接实现。sse仅支持单工通信,客户端无法向服务端发送消息。

1. Api介绍

url: 后端地址(必填)

option: 配置对象(选填)

const eventSource = new EventSource(url, {
    withCredentials:false,//是否携带cookie,默认false
    headers:{},//请求头类型
    retryInterval:1000//与服务器失去连接时,重新连接的间隔时间
});

2. close()

eventSource.close()

3.onopen()

eventSource.onopen = function(e){
    console.log('连接成功')
}

4.onerror()

eventSource.onerror = function(e){
    console.log('连接失败')
}

5.onmessage()

eventSource.onmessage = function(e){
    console.log('后端发送的消息',e)
}

6.操作例子

    const sse = new EventSource("http://localhost:3000/json");
    sse.onmessage = function(e) {
        console.log('服务端发送的消息',e)
    }
    sse.onerror = funcction(e) {
        console.log('连接失败')
    }

三:sendBeacon

sendBeacon方法可用于通过 HTTP POST 将少量数据 异步 传输到 Web 服务器。它的操作十分简单

navigator.sendBeacon(url,data)

特点

优点

  1. 异步执行,不受页面卸载阻塞
  2. 支持跨域(太酷啦)

缺点

  1. 只支持post
  2. 仅发送少量数据64kb
  3. 无法自定义请求头格式,需要和后端约定好格式

使用场景

  1. 埋点
  2. 发送用户反馈

使用

//定义请求头格式
let headers = {
  type: 'application/x-www-form-urlencoded'
};
//借助blob拼接数据和请求头
let blob = new Blob([JSON.stringify({name:"dzp"})], headers);
//发送数据
navigator.sendBeacon(this.data.requestUrl,blob)

四:websocket

sse适用于单工通信(服务端推送),那么websocket专门用于双工通信(客户端与服务端都可以发送接收消息)

1.基本API

创建对象

let websocket = new WebSocket('ws://localhost:3001');

监听连接成功

websocket.onopen = function(e) {
  console.log('连接服务端成功')
}

监听连接断开

websocket.onclose = function(e) {
  console.log('断开连接')
}

发送消息到服务端

   websocket.send(msg)
   

接收服务端消息

   websocket.onmessage = function(e) {
      console.log('消息',e)
   }
   

主动断开连接

   websocket.close()
   
   

2. 1对1通信

前端

  <body>
      <button onclick="sendMsg()">发送消息</button>
      <script>
        let websocket = new WebSocket('ws://localhost:3001');
        websocket.onmessage = function(e) {
          console.log('服务端发送的消息',e.data)
        }
        websocket.onopen = function(e) {
          console.log('连接服务端成功')
        }
        
        function sendMsg() {
          if(websocket.readyState === 1) {
            websocket.send(Math.random()*10)
          }
        } 
      </script>
    </body>

后端 koa2

  const ws = new WebSocket.Server({ port: 3001 });
    ws.on('connection', socket => {//监听连接成功
      socket.on('message', msg => {//获取客户端消息
        let data = msg.toString()
        socket.send(data)//向客户端发送消息
      });
    });

效果

两个客户端独立的向服务端发送消息,服务端将客户端发送的消息传递给前端。

334.gif

3.群聊通信

上面的案例展示了如何单聊,那么如何实现广播?也就是群聊的方式?yeah,服务端在收到任意客户端消息时,拿到所有客户端,然后将当前信息广播出去就行了。

   **前端**

  <body>
      <button onclick="sendMsg()">发送消息</button>
      <script>
        let websocket = new WebSocket('ws://localhost:3001');
        websocket.onmessage = function(e) {
          console.log('服务端发送的消息',e.data)
        }
        websocket.onopen = function(e) {
          console.log('连接服务端成功')
        }
        
        function sendMsg() {
          if(websocket.readyState === 1) {
            websocket.send(Math.random()*10)
          }
        } 
      </script>
    </body>

后端 koa2

  const ws = new WebSocket.Server({ port: 3001 });
    ws.on('connection', socket => {//监听连接成功
      socket.on('message', msg => {//获取客户端消息
        let data = msg.toString()
        ws.clients.forEach(item=>{//群发消息
          item.send(data)
        })
      });
    });

效果

两个客户端独立的向服务端发送消息,服务端将客户端发送的消息传输到每个客户端。

335.gif

4.心跳包

websocket在长时间未通信、弱网等情况下会自动关闭连接,为了保持其长连接效果,我们可以在前端或者后端开启定时器持续的向对方发送“心跳“数据保证长连接。

前端

 <body>
  <button onclick="sendMsg()">发送消息</button>
  <script>
    let websocket = new WebSocket('ws://localhost:3001');
    websocket.onmessage = function(e) {
      let data = JSON.parse(e.data)
      if(data.state === 2) {//忽略心跳包数据
        console.log('客户端受到消息',data.msg)
      }
    }
    websocket.onopen = function(e) {
      console.log('连接服务端成功')
    }
    websocket.onclose = function(e) {
      console.log('断开连接')
    }
    function sendMsg() {
      if(websocket.readyState === 1) {
        websocket.send(Math.random()*10)
      }
    } 

  </script>
</body>

后端

  const state = {
      HEART:1,
      MESSAGE:2
  }
  const ws = new WebSocket.Server({ port: 3001 });
  ws.on('connection', socket => {
      socket.on('message', msg => {//获取客户端消息
        let data = msg.toString()
        ws.clients.forEach(item=>{//群发消息
          item.send(JSON.stringify({
            state:state.MESSAGE,
            msg:data
          }))
        })
      });
      let timer = null
      const sendHeartMsg = () => {
        if(socket.readyState === 1) {//连接成功状态
          socket.send(JSON.stringify({
            state:state.HEART,
            msg:"心跳检测数据"
          }))
        }else { 
          clearInterval(timer)
        }
      }
      timer = setInterval(sendHeartMsg,5000)
    });