当前位置:   article > 正文

微信小程序 WebSocket 通信 —— 在线聊天_微信小程序socket通信

微信小程序socket通信

         * 源码已经上传到资源处,需要的话点击跳转下载 |  源码下载

        在Node栏目就讲到了Socket通信的内容,使用Node实现Socke通信,还使用两个流行的WebSocket 库,ws 和 socket.io,在小程序中的WebSocket接口和HTML5的WebSocket基本相同,可以实现浏览器与服务器之间的全双工通信。那么本篇就来讲关于微信小程序实现WebSocket通信完成在线聊天。

客户端流程

        这里的客户端也就是微信小程序了,同时还需要使用Node搭载一个服务器,WebSocket 是客服端与服务器之间专门建立的一条通道,先来了解一下过程:

        通过 wx.connectSocket 来创建 WebSocket 连接,来连接搭载好的Node服务器,连接之后发送数据可以通过 wx.sendSocketMessage ,可以发送数据到达客户端,同时也需要监听接收来自客户端发出的消息事件可以使用 wx.onSocketMessage ,知道这个流程之后,来看一下服务器的搭载流程。

服务器流程

        使用Node搭载服务器,WebSocket 服务是建立在HTTP之上的,可以通过引入 http 模块,使用 http.createServer() 创建 HTTP服务器,安装WebSocket库,当然这里可以使用Node中net模块,这里附上可供你参考的篇目: 参考 |   参考1  |  参考2

         通过 WebSocket库来创建 WebSocket服务器,同时还需要设置 autoAcceptConnections ,对客服端发送的数据进行一个监控,以及关闭连接的监控,此外还可以进行其他的监控像错误,以及控制台的输入等操作。


图解

        用一个图来简单概述一下:

         下面来使用WebSokcet通信实现在线聊天,那先来看看需要完成的效果内容:


        以上就是接下来要完成的一个场景,先从小程序入手:

1. 聊天界面编写

        编写小程序的聊天界面,这里也不再多讲,主要还是讲一下注意点,聊天的数据不可能是一条两条,所以它应该是一个scroll-view滚动的,底部的输入框是固定在底部的,同时要避免底部会把最后的消息数据给遮挡了,聊天数据可以数组保存,然后通过wx:for渲染,是左边的还是右边发出的数据可以通过wx:if来进行判断显示左边还是右边,不破坏原型的DOM结构可以用block标签。

  1. <!--pages/wxchat/wxchat.wxml-->
  2. <!-- 聊天信息 -->
  3. <view class="content">
  4. <scroll-view class="content-info" scroll-y scroll-top="{{scrollTop}}">
  5. <view class="content-list">
  6. <view class="content-li" wx:for="{{infoList}}" wx:key="id">
  7. <!-- 右边 -->
  8. <block wx:if="{{item.role === 'self'}}">
  9. <view class="right-info">
  10. <image class="myhead" src="{{head.self}}"></image>
  11. <text class="myinfo">{{item.content}}</text>
  12. </view>
  13. </block>
  14. <!-- 左边 -->
  15. <block wx:else>
  16. <view class="left-info">
  17. <image class="myhead" src="{{head.server}}"></image>
  18. <text class="myinfo">{{item.content}}</text>
  19. </view>
  20. </block>
  21. </view>
  22. </view>
  23. </scroll-view>
  24. </view>
  25. <!-- 操作区 -->
  26. <view class="foot-input">
  27. <input type="text" class="send-input" placeholder="请输入聊天内容..." value="{{message}}" bindinput="handleChange"/>
  28. <view class="send-btn" bindtap="handleSend">发送</view>
  29. </view>
  1. /* pages/wxchat/wxchat.wxss */
  2. page{
  3. height: 100%;
  4. }
  5. .content{
  6. height: 100%;
  7. display: flex;
  8. }
  9. .content-info .content-list{
  10. margin-bottom: 88rpx;
  11. }
  12. /* 信息 */
  13. .content .content-info .content-list .content-li{
  14. clear: both;
  15. overflow: hidden;
  16. }
  17. .left-info{
  18. clear: both;
  19. margin: 20rpx 20rpx;
  20. }
  21. .left-info .myhead{
  22. float: left;
  23. width: 88rpx;
  24. height: 88rpx;
  25. /* background:#efefef; */
  26. }
  27. .left-info .myinfo{
  28. display: block;
  29. float: left;
  30. background: #75c475;
  31. max-width: 490rpx;
  32. margin-top: 10rpx;
  33. margin-left: 20rpx;
  34. padding: 10rpx 18rpx;
  35. border-radius: 20rpx;
  36. }
  37. .left-info::after{
  38. content:'';
  39. clear: both;
  40. display: block;
  41. height: 0;
  42. visibility: hidden;
  43. }
  44. .right-info{
  45. clear: both;
  46. margin: 10rpx 20rpx;
  47. }
  48. .right-info .myinfo{
  49. display: block;
  50. float: right;
  51. background: #efefef;
  52. max-width: 490rpx;
  53. margin-top: 10rpx;
  54. margin-right: 20rpx;
  55. padding: 10rpx 18rpx;
  56. border-radius: 20rpx;
  57. }
  58. .right-info .myhead{
  59. float: right;
  60. width: 88rpx;
  61. height: 88rpx;
  62. /* background-color: #efefef; */
  63. }
  64. .right-info::after{
  65. content:'';
  66. clear: both;
  67. display: block;
  68. height: 0;
  69. visibility: hidden;
  70. }
  71. /* 底部 */
  72. .foot-input{
  73. position: fixed;
  74. bottom: 0;
  75. border-top: 1px solid #DDDDDD;
  76. width: 750rpx;
  77. height: 88rpx;
  78. line-height: 88rpx;
  79. background: #ffffff;
  80. }
  81. .foot-input .send-input{
  82. float: left;
  83. width: 560rpx;
  84. max-width: 600rpx;
  85. margin: 16rpx 0 0 20rpx;
  86. padding: 0 10rpx;
  87. }
  88. .foot-input .send-btn{
  89. float: right;
  90. margin: 11rpx 20rpx 0 0;
  91. width: 120rpx;
  92. height: 66rpx;
  93. line-height: 66rpx;
  94. text-align: center;
  95. background: #16AA51;
  96. color: #ffffff;
  97. border-radius: 10rpx;
  98. }

2. 小程序创建服务器连接

        小程序要接入WebSocketServer服务器,首先要创建服务器连接,可以通过wx.connectSocket() 方法来创建连接,在小程序初始加载的时候就可以进行,同时还可以使用 wx.showToast() 方法提示接入成功与否;

  1. /* pages/wxchat/wxchat.js*/
  2. Page({
  3. onLoad:function(){
  4. this.createSocketServer();
  5. },
  6. // 创建服务器连接
  7. createSocketServer(){
  8. // 服务器地址开头 ws/wss
  9. url: 'ws://127.0.0.1:3000'
  10. }
  11. // 监控接入与否
  12. wx.onSocketOpen(()=>{
  13. // 接入成功
  14. wx.showToast({
  15. title: 'Socket接入成功',
  16. icon: 'success'
  17. })
  18. // 接入问候语
  19. })
  20. // 监控信息 - 待写
  21. // wx.onSocketMessage(()=>{ ... })
  22. // 监控关闭
  23. wx.onSocketClose(()=>{
  24. // 服务器Socket连接关闭
  25. wx.showToast({
  26. title: 'Socket已关闭'
  27. icon: 'error'
  28. })
  29. })
  30. // 监控错误
  31. wx.onSocketError((err)=>{
  32. console.log('接入异常',err);
  33. })
  34. })

3. 搭载Node服务器 - WebSocket服务器

        搭载Node服务器,WebSocket服务是建立在HTTP上,所以需要先引用http模块创建HTTP服务器再创建WebSocket服务器,在这里使用第三方的websocket库。

# 初始化 —— 在创建好的目标目录下进行初始化

npm init -y

 # 使用npm 安装 websocket 库

npm i websocket

# [可选] 使用 npm 安装 nodemon 

npm i nodemon

   * 不安装运行index.js文件使用每次修改后要执行     —— node index.js

   * 安装运行index.js文件使用每次修改不需要手动执行  

# 使用 npm 安装 moment.js —— 格式化时间

npm i moment -S

# 创建 index.js 文件进行编写代码

  1. /* 服务器index.js文件 */
  2. const http = require('http');
  3. const WebSocketServer = require('websocket').server;
  4. const moment = require('moment')
  5. // 创建HTTP服务器
  6. const httpServer = http.createServer((req,res)=>{
  7. res.writeHead(404);
  8. res.end();
  9. })
  10. // 创建websocket服务器
  11. const wsServer = new WebSocketServer({
  12. httpServer,
  13. autoAcceptConnections : true // 自动接受连接
  14. })
  15. // 监控接入
  16. wsServer.on('connect',(connection)=>{
  17. // 监控数据信息message
  18. connection.on('message',(msg)=>{
  19. console.log('>> message' , msg);
  20. if( msg.type === 'utf8' ){
  21. var data = {
  22. content : '[自动回复] : 请等待用户接入回复...',
  23. date : moment(new Date()).format('YYYY-D-M , h:mm a')
  24. }
  25. connection.sendUTF( JSON.stringify(data) )
  26. }
  27. })
  28. // 监控关闭
  29. connection.on('close',()=>{
  30. console.log('Socket服务关闭');
  31. })
  32. })
  33. // 监听 3000 端口
  34. httpServer.listen('3000',()=>{
  35. console.log('SERVER RUNNING ...')
  36. })

4. 客户端发送数据信息 

        在input输入框中输入数据信息,通过在input框中绑定bindinput来监听获取输入框中的数据,将input框的value = {{ message }} ,便于做清空数据框操作。在点击"发送"按钮时将input中获取的信息通过sendSocketMessage 发送到服务器。

  1. !--pages/wxchat/wxchat.js-->
  2. Page({
  3. data:{
  4. head:{
  5. self:'https://profile.csdnimg.cn/8/D/A/2_weixin_52203618',
  6. server:'https://img2.baidu.com/it/u=4237756909,3713889849&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400'
  7. },
  8. },
  9. onLoad:function(){
  10. this.createSocketServer()
  11. },
  12. // 创建服务器连接
  13. createSocketServer(){
  14. ...
  15. },
  16. message:'', // 待接收发送的消息
  17. // 获取Input框内的数据
  18. handleChange(opt){
  19. this.message = opt.detail.value
  20. }
  21. // 发送按钮触发事件
  22. handleSend(){
  23. // 发送的内容不为空
  24. if(this.message){
  25. // 发送
  26. wx.sendSocketMessage({
  27. data : this.message
  28. })
  29. // 收集我发出的信息 - 待写
  30. }else{
  31. wx.showToast({
  32. title: '请输入聊天内容',
  33. icon: 'none',
  34. duration: 1000
  35. })
  36. }
  37. }
  38. })

5. 收集发送的数据信息

        通过wx.sendSocketMessage()将内容发送出去,需要将内容进行一个收集,收集到一个数组当中去,然后在页面通过wx:for的渲染方式显示出来,下面是对发送的数据信息进行收集:

  1. <!--pages/wxchat/wxchat.js-->
  2. Page({
  3. data:{
  4. head:{ ... }, // 用户头像
  5. infoList:[] // 待收集数据信息
  6. },
  7. onLoad:function(){ ... },
  8. message: '', // 待发送的数据信息
  9. id: 0, // 数据信息标识
  10. // 发送按钮触发事件
  11. handleSend(){
  12. if(this.message){
  13. wx.sendSocketMessage({ data: this.message })
  14. // 收集我发出的信息
  15. var list = this.data.infoList
  16. list.push({
  17. id: this.id++ ,
  18. content: this.message ,
  19. role: 'self' // 标识 —— 客户端发出
  20. })
  21. // 更新
  22. this.setData({
  23. infoList : list
  24. message : '' // 清空输入框
  25. })
  26. // 聊天视角 - 待写
  27. }else{
  28. wx.showToast({
  29. title: '请输入聊天内容',
  30. icon: 'none',
  31. duration: 1000
  32. })
  33. }
  34. }
  35. })

6. 接入服务器问候语

        接入服务器之后,客户端会自动发送 "你好" 的问候语;那么message是待发送的数据信息,监控客户端接入服务器的时候可以为message进行赋值,再调用handSend()方法发送,当然你可以调整一下handSend()方法,将其作为参数,这里就不做调整了,那么此时message绑定在input框的value值上,需要对message进行清空,否则当你再次点击发送的时候,没有输入任何数据也会发送 "你好" 的数据信息;

  1. Page({
  2. data:{ ... },
  3. onLoad:function(){ this.createSocketServer() },
  4. // 创建服务器连接
  5. createSocketServer(){
  6. wx.connectSocket({ url: 'ws://127.0.0.1:3000/' })
  7. // 监控接入
  8. wx.onSocketOpen(() => {
  9. wx.showToast({
  10. title: 'Socket接入成功',
  11. icon: 'success'
  12. })
  13. // 接入问候语
  14. this.message = '你好'
  15. this.handleSend()
  16. this.message = ''
  17. })
  18. ...
  19. }
  20. })

7. 服务器发送数据信息到客户端

        客户端发送的数据信息在服务器中通过数据的监控可以知道,在前面已经编写了这段:

  1. wsServer.on('connect',(connection)=>{
  2. // 监控是否有message信息
  3. connection.on('message',(msg)=>{
  4. console.log('>> message' , msg);
  5. if( msg.type === 'utf8'){
  6. var data = {
  7. content: '[自动回复] : 请等待用户接入回复...',
  8. date: moment(new Date()).format('YYYY-D-M , h:mm a')
  9. }
  10. connection.sendUTF( JSON.stringify(data) )
  11. }
  12. })
  13. })

         接下来是在服务器进行发送数据到客户端,那么服务器可以通过在控制台的输入发送到客户端,监控控制台的输入进行获取通过sendUTF发送到客户端。

  1. /* 服务器index.js文件 */
  2. ...
  3. wsServer.on('connect',(connection)=>{
  4. // 监控是否有message信息
  5. connection.on('message',(msg)=>{ ... })
  6. // 监控关闭
  7. connection.on('close',()=>{ ... })
  8. // 监控控制台输入
  9. process.stdin.on('data',(data)=>{
  10. var data = data.toString().trim() // 清除前后空格
  11. data = {
  12. content : data,
  13. date : moment(new Date()).format('YYYY-D-M , h:mm a')
  14. }
  15. connection.sendUTF(JSON.stringify(data)); // 发送
  16. })
  17. })
  18. ...

        服务器发送数据信息到客户端,那么需要在客户端进行监控数据信息

8. 客户端监控收集服务端发来的数据信息

         服务器发来的数据信息,在小程序客户端上需要对其进行一个数据信息的监控,同时还需要将这些数据信息使用数组收集起来,在页面使用wx:for渲染交互信息。

  1. <!--pages/wxchat/wxchat.js-->
  2. Page({
  3. data:{ ... },
  4. onLoad:function(){ ... },
  5. message: '', // 待发送的数据信息
  6. id: 0, // 数据信息标识
  7. createSocketServer(){
  8. // 创建服务器连接
  9. wx.connectSocket({url: 'ws://127.0.0.1:3000/'})
  10. // 监控接入
  11. wx.onSocketOpen(()=>{ ... })
  12. // 监控信息
  13. wx.onSocketMessage((msg)=>{
  14. var result = JSON.parse(msg.data);
  15. result.id = this.id++
  16. result.role = 'Server' // 标识 —— 服务端发出
  17. // 收集
  18. var list = this.data.infoList
  19. list.push(result)
  20. // 更新
  21. this.setData({
  22. infoList : list
  23. })
  24. // 聊天视角 - 待写
  25. })
  26. }
  27. })

9 .定位到消息处 —— 聊天视角

        能够在页面上正常的渲染客户端和服务器所发出的数据信息,接下来需要处理聊天视角的问题,聊天界面的聊天数据随着发送的增多会是聊天界面出现滑动状态 scroll-view ,那么当超出的聊天数据信息就需要定位到最底部发出消息的视角,不需要手动的向下滑动到发送数据信息的位置。通过 scroll-view 的标签中的scroll-top属性,同时要对每一个发送数据信息的内容高度进行计算,然后进行定位,那么可以对渲染的每一个 content-li 的高度进行计算。

  1. <!--pages/wxchat/wxchat.js-->
  2. Page({
  3. data: { ...
  4. scrolltop: 0 // 默认滑动定位
  5. },
  6. onLoad:function(){ ... }
  7. message: '', // 待发送的数据信息
  8. id: 0, // 数据信息标识
  9. createSocketServer(){
  10. // 创建连接
  11. wx.connectSocket({ ... })
  12. // 监控接入
  13. wx.onSocketOpen(()=>{ ... })
  14. // 监控信息
  15. wx.onSocketMessage((msg)=>{
  16. ...
  17. // 聊天视角
  18. this.rollingBottom()
  19. })
  20. },
  21. handleChange(opt){ ... },
  22. handleSend(){
  23. if(this.message){
  24. ...
  25. // 聊天视角
  26. this.rollingBottom()
  27. }else{
  28. ...
  29. }
  30. },
  31. // 聊天视角调整方法
  32. rollingBottom(){
  33. wx.createSelectorQuery().selectAll('.content-li').boundingClientRect(results=>{
  34. results.forEach(result=>{
  35. console.log(result)
  36. this.setData({
  37. scrollTop : result.bottom
  38. })
  39. })
  40. }).exec()
  41. }
  42. })

10 .状态设置优化 

        当客户端点击发送数据信息,服务器都会返回这个自动回复的内容,显然不友好,需要什么效果呢,就是当服务器不在线状态时,客户端发送什么,服务器仅回复【自动回复】来提示客户端当前不在线,如果服务器在控制台输出作出答复返回给客户端,此时服务器就是在线状态,那么当客户端再次发来的时候,服务器就不再继续返回【自动回复】

  1. /* 服务器index.js文件 - 完整 */
  2. const http = require('http');
  3. const WebSocketServer = require('websocket').server;
  4. const moment = require('moment')
  5. // 在线状态
  6. let onLineStatus = false // 服务器默认不在线
  7. // 创建Http服务器
  8. const httpServer = http.createServer((req,res)=>{
  9. res.writeHead(404);
  10. res.end();
  11. })
  12. // 创建ws服务器
  13. const wsSercer = new WebSocketServer({
  14. httpServer,
  15. autoAcceptConnections : true
  16. })
  17. wsSercer.on('connect',(connection)=>{
  18. // 监控是否有message信息
  19. connection.on('message',(msg)=>{
  20. console.log('>> message',msg)
  21. // if( msg.type === 'utf8'){
  22. if( msg.type === 'utf8' && !onLineStatus){
  23. var data = {
  24. content: '[自动回复] : 请等待用户接入回复...',
  25. date: moment(new Date()).format('YYYY-D-M , h:mm a')
  26. }
  27. connection.sendUTF( JSON.stringify(data) )
  28. }
  29. })
  30. // 监控关闭
  31. connection.on('close',()=>{
  32. console.log('close')
  33. })
  34. // 接收控制台输入
  35. process.stdin.on('data',(data)=>{
  36. var data = data.toString().trim() // 清除前后空格
  37. data = {
  38. content : data,
  39. date : moment(new Date()).format('YYYY-D-M , h:mm a')
  40. }
  41. connection.sendUTF( JSON.stringify(data) )
  42. // 在线状态
  43. onLineStatus = true
  44. })
  45. })
  46. httpServer.listen('3000',()=>{
  47. console.log('SERVER RUNNING ...')
  48. })

        以上就完成了整个使用WebSocket实现通信的代码,下面来进行测试一下吧效果吧!


测试效果

1. 启动服务器 node index.js / nodemon index.js

 2. 刷新一下微信小程序

3. 在控制台上输入发送数据信息 

 4. 客户端接收并回复

        以上就是这篇文章的全部内容了,这里可以借用局域网的url地址更换,可以实现一个简单的聊天室功能,那么本篇就到这,感谢大家的支持!!!

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/291583
推荐阅读
相关标签
  

闽ICP备14008679号