什么是webSocket?怎么使用webSocket中的第三方socket.io包

1,294 阅读2分钟

http 协议

  1. http中文意思: 超文本传输协议, 定义服务器和客户端的传送格式

  2. 请求发送的数据包, 叫请求报文, 格式如下

在这里插入图片描述

  1. 响应回来的数据包, 叫响应报文, 格式如下

在这里插入图片描述

HTTP 协议:客户端与服务器建立通信连接之后,服务器端只能被动地响应客户端的请求,无法主动给客户端发送消息。

一次请求才能对应一次响应

由于 http 是一次请求对应一次响应,无法达到即时通信的效果,所以在后面的 html5 中提出了一个新的协议 websocket 来实现即时通信的效果

什么是 websocket

websocket 是一种网络通信协议,是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通 信的协议,这个对比着 HTTP 协议来说,HTTP 协议是一种无状态的、无连接的、单向的应 用层协议,通信请求只能由客户端发起,服务端对请求做出应答处理。HTTP 协议无法实现 服务器主动向客户端发起消息,websocket 连接允许客户端和服务器之间进行全双工通信, 以便任一方都可以通过建立的连接将数据推送到另一端。websocket 只需要建立一次连接, 就可以一直保持连接状态

socket.io包使用

1. 安装socket.io包

npm install socket.io-client@4.0.0 -D
//
yarn add socket.io-client@4.0.0 -D

2. 在组件内引入包

// 导入 socket.io-client 包
import { io } from 'socket.io-client'

// 定义变量,存储 websocket 实例
let socket = null

3. 创建socket服务

created() {
    // ...
    
    // 创建客户端 websocket 的实例
    socket = io('http://地址', {
        query: {
            token: this.token
        },
        transports: ['websocket']
    })
}

4. 监听是否连接成功

只有连接内置事件执行了, 才能进行后续操作

created() {
  // 建立连接的事件
  socket.on('connect', () => {
    console.log('与服务器建立了连接')
  })
}

5. 在组件销毁前, 关闭服务

// 组件被销毁之前,清空 sock 对象
beforeDestroy() {
  // 关闭连接
  socket.close()

  // 销毁 websocket 实例对象
  socket = null
},

6. 在created监听socket的消息

created() {
    // ...

    // 接收到消息的事件
    socket.on('message', data => {
      // 把服务器发送过来的消息,存储到 list 数组中
      this.list.push({
        name: 'xs',
        msg: data.msg
      })
    })
},

7. 在 send事件中, 把服务器发来的数据装到数组里

sendFn () {
    // 判断内容是否为空
    if (!this.word) return

    // 添加聊天消息到 list 列表中
    this.list.push({
        name: 'me',
        msg: this.word
    })
}

8. 客户端调用 socket.emit('message', 消息内容) 方法把消息发送给 websocket 服务器

// 向服务端发送消息
sendFn () {
    // 判断内容是否为空
    if (!this.word) return

    // 添加聊天消息到 list 列表中
    this.list.push({
        name: 'me',
        msg: this.word
    })

    // 把消息发送给 websocket 服务器
    socket.emit('message', {
        msg: this.word,
        timestamp: new Date().getTime()
    })

    // 清空文本框的内容
    this.word = ''
}

客服小思机器人

<template>
  <div class="container">
    <!-- 固定导航 -->
    <van-nav-bar fixed left-arrow @click-left="$router.back()" title="小思同学"></van-nav-bar>

    <!-- 聊天主体区域 -->
    <div class="chat-list">
      <div v-for="(item, index) in list" :key="index">
        <!-- 左侧是机器人小思 -->
        <div class="chat-item left" v-if="item.name === 'xs'">
          <van-image fit="cover" round src="https://img.yzcdn.cn/vant/cat.jpeg" />
          <div class="chat-pao">{{ item.msg }}</div>
        </div>

        <!-- 右侧是当前用户 -->
        <div class="chat-item right" v-else>
          <div class="chat-pao">{{ item.msg }}</div>
          <van-image fit="cover" round :src="$store.state.photo" />
        </div>
      </div>
    </div>

    <!-- 对话区域 -->
    <div class="reply-container van-hairline--top">
      <van-field placeholder="说点什么..." v-model="word">
        <template #button>
          <span style="font-size:12px;color:#999" @click="sendFn">提交</span>
        </template>
      </van-field>
    </div>
  </div>
</template>

<script>
import store from '@/store/index.js'
import { io } from 'socket.io-client'
export default {
  name: 'Chat',
  data() {
    return {
      word: '',
      socket: null,
      list: [
        // 只根据 name 属性,即可判断出这个消息应该渲染到左侧还是右侧
        { name: 'xs', msg: 'hi,你好!我是小思' },
        { name: 'me', msg: '我是编程小王子' }
      ]
    }
  },
  methods: {
    sendFn() {
      this.socket.emit('message', {
        msg: this.word,
        timestamp: Date.now()
      })
      this.list.push({ name: 'me', msg: this.word })
      this.word = ''
      // 聊天内容置底
      this.$nextTick(() => {
        const height1 = document.querySelector('.chat-list').clientHeight
        const height = document.querySelector('.chat-list').scrollHeight
        document.querySelector('.chat-list').scrollTop = height - height1
      })
    }
  },
  created() {
    this.socket = io('http://url地址', {
      query: {
        token: store.state.token
      },
      transports: ['websocket']
    })
    // 建立连接的事件
    this.socket.on('connect', () => {
      console.log('与服务器建立了连接')
    })
    this.socket.on('message', data => {
      // console.log(data)
      this.list.push({ name: 'xs', msg: data.msg })
      // 聊天内容置底
      this.$nextTick(() => {
        const height1 = document.querySelector('.chat-list').clientHeight
        const height = document.querySelector('.chat-list').scrollHeight
        document.querySelector('.chat-list').scrollTop = height - height1
      })
    })
  }
}
</script>

<style lang="less" scoped>
.container {
  height: 100%;
  width: 100%;
  position: absolute;
  left: 0;
  top: 0;
  box-sizing: border-box;
  background: #fafafa;
  padding: 46px 0 50px 0;
  .chat-list {
    height: 100%;
    overflow-y: scroll;
    .chat-item {
      padding: 10px;
      .van-image {
        vertical-align: top;
        width: 40px;
        height: 40px;
      }
      .chat-pao {
        vertical-align: top;
        display: inline-block;
        min-width: 40px;
        max-width: 70%;
        min-height: 40px;
        line-height: 38px;
        border: 0.5px solid #c2d9ea;
        border-radius: 4px;
        position: relative;
        padding: 0 10px;
        background-color: #e0effb;
        word-break: break-all;
        font-size: 14px;
        color: #333;
        &::before {
          content: '';
          width: 10px;
          height: 10px;
          position: absolute;
          top: 12px;
          border-top: 0.5px solid #c2d9ea;
          border-right: 0.5px solid #c2d9ea;
          background: #e0effb;
        }
      }
    }
  }
}
.chat-item.right {
  text-align: right;
  .chat-pao {
    margin-left: 0;
    margin-right: 15px;
    &::before {
      right: -6px;
      transform: rotate(45deg);
    }
  }
}
.chat-item.left {
  text-align: left;
  .chat-pao {
    margin-left: 15px;
    margin-right: 0;
    &::before {
      left: -5px;
      transform: rotate(-135deg);
    }
  }
}
.reply-container {
  position: fixed;
  left: 0;
  bottom: 0;
  height: 44px;
  width: 100%;
  background: #f5f5f5;
  z-index: 9999;
}
</style>
text-align: left;
  .chat-pao {
    margin-left: 15px;
    margin-right: 0;
    &::before {
      left: -5px;
      transform: rotate(-135deg);
    }
  }
}
.reply-container {
  position: fixed;
  left: 0;
  bottom: 0;
  height: 44px;
  width: 100%;
  background: #f5f5f5;
  z-index: 9999;
}
</style>

效果

在这里插入图片描述