排查 Socket.IO 常见问题

适用于 Socket.IO 的 Web PubSub 是基于 Socket.IO 库生成的。 使用 Azure 服务时,问题可能在于服务或库。

要查找问题的根源,可以通过暂时从应用程序中移除适用于 Socket.IO 的 Web PubSub 来隔离 Socket.IO 库。 如果应用程序在移除后按预期工作,则根本原因可能在于 Azure 服务。

使用本文查找服务常见问题的解决方案。 此外,还可以 在服务器端启用日志记录,以检查 Socket.IO 应用的行为(如果列出的解决方案都无济于事)。

如果怀疑 Socket.IO 库出现问题,请参阅 Socket.IO 库的文档

服务器端

包导入不正确

可能的错误

TypeError: (intermediate value).useAzureSocketIO is not a function

根本原因

如果在项目中使用 TypeScript,则可能会看到此错误。 这是由于包导入不正确造成的。

// Bad example
import * as wpsExt from "@azure/web-pubsub-socket.io"

如果在导入后未使用或引用包,则 TypeScript 编译器的默认行为将不是发出已编译的 .js 文件中的包。

解决方案

请改用 import "@azure/web-pubsub-socket.io"。 此导入语句可强制 TypeScript 编译器在编译后的 .js 文件中包含包,即使未在源代码中的任何位置引用该包也是如此。 在 TypeScript 社区中详细了解此常见问题。

// Good example. 
// It forces TypeScript to include the package in compiled .js file.
import "@azure/web-pubsub-socket.io"

客户端

路径选项不正确

可能的错误

GET <web-pubsub-endpoint>/socket.io/?EIO=4&transport=polling&t=OcmE4Ni 404 未找到

根本原因

Socket.IO 客户端是在没有正确 path 选项的情况下创建的。

// Bad example
const socket = io(endpoint)

解决方案

添加值为 /clients/socketio/hubs/eio_hub 的正确的 path 选项。

// Good example
const socket = io(endpoint, {
    path: "/clients/socketio/hubs/eio_hub",
});

Socket.IO 终结点的 Web PubSub 不正确

可能的错误

GET <non-web-pubsub-endpoint>/socket.io/?EIO=4&transport=polling&t=OcmE4Ni 404 未找到

根本原因

Socket.IO 客户端是在没有适用于 Socket.IO 终结点的正确 Web PubSub 的情况下创建的。 例如:

// Bad example. 
// This example uses the original Socket.IO server endpoint. 
const endpoint = "socketio-server.com";
const socket = io(endpoint, {
    path: "/clients/socketio/hubs/<Your hub name>",
});

在使用适用于 Socket.IO 的 Web PubSub 时,客户端会与 Azure 服务建立连接。 创建 Socket.IO 客户端时,需要使用适用于 Socket.IO 资源的 Web Pubsub 的终结点。

解决方案

允许 Socket.IO 客户端将终结点用于适用于 Socket.IO 资源的 Web PubSub。

// Good example.
const webPubSubEndpoint = "<web-pubsub-endpoint>";
const socket = io(webPubSubEndpoint, {
    path: "/clients/socketio/hubs/<Your hub name>",
});

为同一包安装了多个版本

可能的错误

服务器抛出错误:

  const io = await require('socket.io')(server).useAzureSocketIO(wpsOptions);        
                                                  ^
TypeError: require(...)(...).useAzureSocketIO is not a function

根本原因

socket.ioengine.io 包添加到依赖项字段下的 package.json,而 SDK 包 @azure/web-pubsub-socket.io 在内部指定其他版本。 例如:

"dependencies": {
    "@azure/web-pubsub-socket.io": "1.0.1-beta.6",
    "socket.io": "4.6.1"
},

yarn install 后,将安装两个不同的版本。 可以通过运行 npm list socket.io 进行验证。 此命令应显示两个版本的 socket.io 包:

demo@0.0.0 G:\demo
├─┬ @azure/web-pubsub-socket.io@1.0.0-beta.6
│ └── socket.io@4.7.1
└── socket.io@4.6.1

解决方案

解决方案取决于是否需要自定义版本的 socket.ioengine.io 包。

  • 不需要自定义版本的 socket.io/engine.io 包,只需删除 package.json 依赖项中的 socket.io/engine.io 即可。 例如:
"dependencies": {
    "@azure/web-pubsub-socket.io": "1.0.1-beta.6",
},
  • socket.io/engine.io 包的自定义版本是必需的,在这种情况下,package.json 可以是:
"dependencies": {
    "@azure/web-pubsub-socket.io": "1.0.1-beta.6",
    "socket.io": "4.6.1"
},

然后,应运行 yarn install --flat。 它安装所有依赖项,但每个包只允许一个版本。 在第一次运行时,它会提示你为每个依赖于多个版本范围的包选择一个版本。 对于我们的情况,它可能会提示你选择 socket.ioengine.ioengine.io-parser 版本等。 根据 socket.ioengine.io的本机实现,确保版本彼此匹配。

最终版本将添加到“resolutions”字段下的“package.json”。

"resolutions": {
  "package-a": "a.b.c",
  "package-b": "d.e.f",
  "package-c": "g.h.i"
}