一)前言

在微信小程上实现聊天功能,大致有三种方式:1)小程序云开发 2)购买第三方IM服务 3)使用自己的服务器自己开发。

这里重要讲使用自己的服务器自己开发,并且是基于vs的开发。

网上提供的解决方案大多都是使用Microsoft.AspNetCore.SignalR来完成,但是通过研究,发现以下问题

1)Microsoft.AspNetCore.SignalR必须基于.NET Framework 4.6.1以上和 .NET core 2.1以上,也就是vs2017以上,最好是vs2019

2)我的开发环境是vs2015,只能使用Microsoft.AspNet.SignalR来实现web端的websocket

【相关知识分享链接】

Microsoft.AspNet.SignalR实现web端聊天:https://www.cnblogs.com/lonelyxmas/p/9153983.html

Microsoft.AspNetCore.SignalR实现小程序端聊天:http://www.likecs.com/show-60549.html

AspNet和AspNetCore差异官方详解:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/version-differences?view=aspnetcore-2.2

二)初步的解决方案

了解清楚以上原因后,在目前环境不变的前提下,初步制定了几种解决方案:

1)使用小程序web-view组件

  在小程序页面内嵌web-view组件,将自己的web页面放入,通过官方JSSDK实现交互,所有逻辑写在服务端。

  注:1、不允许个人类型的小程序使用web-view组件。

              2、web-view会自动铺满整个小程序页面,所有样式必须在web页面里写。

              3、需要将web域名添加到web-view白名单。

              4、iOS下若JSSDK接口调用无响应的情况,可在 web-view 的 src 后面加个#wechat_redirect解决。

              5、iOS下若打开白屏,可用 encodeURIComponent(src)解决。

2)使用Node.js

  具体使用请参考百度

3)通过请求连接

  这是本文的重点,一切都因为没有深入了解websocket的机制,下面作详细介绍。

三)了解websocket机制

  假设我在web端有一个聊天室页面,假设地址为https://www.test.com/chat.html,由于后端Startup.cs使用的是默认目录signalr

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(Star.Web.Startup))]
namespace Star.Web
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();//启动SignalR默认目录:/signalr
        }
    }
}

  浏览器F12打开(以谷歌为例),点击Network,然后刷新页面或在页面发送一个消息,在下面Name里分别会出现negotiate开头和connect开头的Url。

  1)点击negotiate开头的url,在头文件中(Headers)的General的RequestURL,显示访问地址是:

//signalr的negotiate
https://www.text.com/signalr/negotiate?clientProtocol=2.1&clientName=……&connectionData=[{"name":"msghub"}]&_=1576127697147

  整理后的含义为:https://域名/signalr/negotiate?clientProtocol=2.1&url参数&connectionData=[{"name":"Hub名字"}]&_=时间戳

  其中:Hub名字就是继承Hub类里的[HubName("Hub名字")]

  2)点击connect开头的url,在头文件中(Headers)的General的RequestURL,显示访问地址是:

//signalr的connect
wss://www.test.com/signalr/connect?transport=webSockets&clientProtocol=2.1&clientName=……&connectionToken=……&connectionData=[{"name":"msghub"}]&tid=1

  整理后的含义为:wss://域名/signalr/connect?transport=webSockets&clientProtocol=2.1&url参数&connectionToken=Token字符串&connectionData=[{"name":"Hub名字"}]&tid=1

  其中:Token字符串就是上一个请求返回的结果;tid好像是个自增ID,可有可无

  3)当你发送消息,或长时间等待时,会发现Name里还会有start开头,send开头,ping开头的Url

  其中start和ping是自动的,send为集线器hub类暴露的hub方法名

[HubMethodName("send")]
public void Send(string message)
{
    ……
}

  在小程序端,以下代码将会报400错误,并打印“打开Socket,失败!”

wx.connectSocket({
      url: 'wss://www.test.com/signalr',
      header: {
        'content-type': 'application/json'
      },
      success:function(e){
        console.log("连接Socket,成功>>");
      },
      fail:function(e){
        console.log("连接Socket,失败>>");
        console.log(e)
      }
    })

    wx.onSocketOpen(function() {
      console.log("打开Socket,成功!")
    })

    wx.onSocketError(function(res) {
      console.log("打开Socket,失败!")
      console.log(res)
    })

  将上面的url改为以下带token的,则通过并打印“打开Socket,成功!”。注意url请用encodeURIComponent()编码一下

wss://www.test.com/signalr/connect?transport=webSockets&clientProtocol=2.1&clientName=%E7%8E%8B%E6%98%8E&connectionToken=hik62ZcX4LK%2B4GvaRZQgDOeG8r5vgAav9D0XnNx%2BJLas%2F702x8SLJihgcTgZnUilQpLZnkxCNp87ilCRPt1gTvtHn9mLj6QkWArcKHhQ8On4sLerDszn6XkLv69MN49U&connectionData=%5B%7B%22name%22%3A%22msghub%22%7D%5D&tid=2

  打开小程序>>调试器>>Network>>Name下面点击connect开头的文件>>Headers,显示101链接成功!

四)结尾

  websocket原理就是页面先发送一个请求给https://.../signalr/negotiate/...,得到返回的token字符串,再通过wss://.../signalr/connect/...进行websocket连接

  只有了解了以上机制,就可以在小程序内写相应请求了,由于时间关系,不上具体小程序端详细代码了

  【相关参考分享链接】

  全国第一例使用SignalR连接小程序:https://www.cnblogs.com/Vam8023/p/9768216.html

  在Vue page里访问 SignalR:https://blog.csdn.net/qq_28462305/article/details/98319703

12-28 14:38