Bittly WebSocket Mock 服务用于模拟 WebSocket 服务,支持模拟多个 WebSocket 连接, 每个连接可以发送和接收消息。 服务支持通过消息匹配规则,自动回复消息, 支持通过转发的方式 将消息转发到指定的 WebSocket 服务,并将返回的消息转发至客户端。
如何使用 Bittly 模拟一个 WebSocket 服务端
主机
:WebSocket 服务的主机地址端口
:WebSocket 服务的端口路径
:WebSocket 服务的路径,例如 /ws
模式
:支持 文本
和 二进制
两种数据类型字符集
: 当内容模式为文本模式时,可指定数据内容字符集,当字符集为 默认
时, 则使用当前项目指定的字符集。SSL
:是否启用 SSL 加密, 如果启用 SSL 加密, 则需要配置 SSL KEY
和 SSL CERT
SSL KEY
:SSL 证书的私钥SSL CERT
:SSL 证书的公钥启用多客户端模式
: 是否启用多客户端模式客户端离线时自动移除
: 在多客户端模式下, 是否在客户端离线时自动移除自动切换新客户端
: 在多客户端模式下, 当一个新的客户端连接时, 是否自动切换到新的客户端。当启用 SSL 时, 需要配置 SSL 证书, 证书可通过以下方式生成:
# 生成私钥KEY
$ openssl genrsa -out private.pem 2048
# 通过私钥生成CSR证书
$ openssl req -new -key private.pem -out csr.pem
# 通过私钥和CSR生成证书
$ openssl x509 -req -days 365 -in csr.pem -signkey private.pem -out file.crt
上述步骤执行完毕后, 将 private.pem
和 file.crt
的内容分别填入 SSL KEY
和 SSL CERT
中即可。
启动服务器后, 可通过访问 https://{主机}:{端口}
来访测试证书是否配置成功。
例如, 配置主机为 127.0.0.1
, 端口为 5566
, 则可通过访问 https://127.0.0.1:5566
来测试证书是否配置成功。
证书设置成功后, 可通过 wss://{主机}:{端口}
来访问 WebSocket 服务。
在默认情况下,MOCK服务在没有匹配到响应规则时, 不会进行任何数据响应操作。
但是,如果我们希望将部分数据转发到其他服务, 则可以通过 转发
功能来实现。
例如,起初我们设备没有实现任何功能, 则我们可以通过配置响应规则来响应所有请求数据。 当设备实现了部分功能时, 我们可以通过将原规则禁用掉, 从而将部分请求数据转发到真实设备, 其余数据继续由MOCK服务响应。
在配置了转发规则后, 当请求数据未匹配任何规则时, MOCK 服务则会将请求数据转发到指定的服务地址, 转发配置可配置不同类型的通讯方式, 例如可以将串口MOCK服务转发到TCP服务, 也可以将TCP服务转发到串口服务。 但是, 转发的要求是两种服务之间支持同一种数据类型,例如串口和TCP服务都支持文本以及二进制数据,所以可以进行转发。
转发目标通过通讯模块进行配置, 配置完成后可通过刷新按钮刷新转发目标列表, 选择需要转发的目标即可。 对于TCP获取UDP等支持多客户端的服务,仅有在未开启多客户端模式下才能进行转发。
当收到数据后,可能收到的数据不是一个完整的数据包,或者存在多余的数据,这时需要对数据进行分帧处理。
收到数据后直接提交给后续步骤处理,不做任何处理。
配置项
时间
: 超时时间,单位毫秒。当收到数据后,如果在超时时间内没有收到更多数据,则标识该数据为一个完整的数据包,提交给后续步骤处理。 如果在超时时间内收到更多数据,则继续等待。
配置项
换行符
: 换行符。支持\r
, \n
和 \r\n
。当收到数据后,如果收到换行符,则标识该数据为一个完整的数据包,提交给后续步骤处理。 如果没有收到换行符,则继续等待。
假设换行符为 \n
, 收到数据如下:
hello\nworld\n123
则收到的数据帧为:
hello\n
和
world\n
数据末尾的 123
会被保留,等待下一次数据到来。
配置项
长度
: 固定长度,单位字节。当收到数据后,如果收到的数据长度等于固定长度,则标识该数据为一个完整的数据包,提交给后续步骤处理。 如果收到的数据长度小于固定长度,则继续等待。
假设收到数据长度为 13,固定长度为 5,收到的数据如下:
hello12345!!!
则收到的数据帧为:
hello
和
12345
数据末尾的 !!!
会被保留,等待下一次数据到来。
配置项
帧头
: 帧头标识,可选。帧尾
: 帧尾标识,可选。超时
: 超时时间,单位毫秒。当配置了帧头和帧尾时,则当收到数据后,如果收到的数据包含帧头和帧尾,则标识该数据为一个完整的数据包,提交给后续步骤处理。 如果在帧头之前存在数据,则会被忽略, 即仅仅被帧头帧尾包括的内容会被提交给后续步骤处理。
假设帧头为 hello
,帧尾为 world
,收到的数据如下:
hello12345world
则收到的数据帧为:
12345
如果配置了帧头而未配置帧尾,接收到的数据将按以下规则处理:若能识别出下一帧的帧头,则将当前帧头至下一帧帧头之前的数据视为完整数据包, 并提交给后续处理。如果未检测到下一帧帧头,则系统将根据设置的超时时间等待,超时后将已接收的数据作为完整数据包处理。
若仅配置了帧尾而未配置帧头,当接收的数据包含帧尾时,将帧尾之前的所有数据视为一个完整的数据包,并提交给后续处理步骤。
当内容模式为文本时, 帧头和帧尾可以配置为文本,例如 hello
和 world
。
如果内容模式为HEX时,帧头和帧尾可以配置为十六进制,例如 AA BB
和 EE FF
。
配置项
表达式
: 正则表达式。忽略大小写
: 是否忽略大小写。当配置分帧模式为正则表达式时,收到数据后则会进行正则表达式匹配,并将匹配的数据内容作为一个完整的数据包提交给后续步骤处理。
例如,配置正则表达式为 hello.*world
,收到的数据如下:
hello12345world
则收到的数据帧为:
12345
当收到数据后,检查数据是否为一个完整的JSON数据包,如果是则提交给后续步骤处理。
例如,收到的数据如下:
{
"name": "hello",
"age": 18
}
{
"name": "world",
则收到的数据帧为:
{
"name": "hello",
"age": 18
}
当收到数据后,检查数据是否为一个完整的XML数据包,如果是则提交给后续步骤处理。
例如,收到的数据如下:
<name>hello</name>
<age>18
则收到的数据帧为:
<name>hello</name>
在服务运行时, 对于需要临时存储的数据, 可以通过变量来进行存储。 变量的值可以在服务运行时进行修改, 但在服务启动时,将会使用默认值进行初始化。
变量可以在脚本或者模板中使用,
例如在模板中使用变量:
{{ $var("变量名") }}
在脚本中使用变量:
// 获取变量
let value = $this.variableGet("变量名");
// 设置变量
$this.variableSet("变量名", "变量值");
Bittly 的 Websocket Mock 服务支持通过脚本来改变执行流程以及自定义响应内容。 脚本采用 JavaScript
语法,
在服务执行时, Bittly 会将脚本编译为 Javascript Module 并在适当的实际执行对应的函数。
脚本函数可以分为两种类型, 一种是生命周期函数,例如 init
等,
另一种是由用户自定义的函数, 可用于在响应模板以及匹配条件中调用。
init()
初始化函数, 用于初始化脚本环境, 仅在服务启动时执行一次, 如果该函数执行失败,则服务启动失败。
例如
export async function init() {
$this.variableSet('counter', 0);
}
onClientData
当客户端发送数据时, 会调用该函数处理数据,例如追加自定义帧头,帧尾或者解析值到变量等,该函数必须返回处理后的数据。
例如
export async function onClientData( data ) {
return data;
}
beforeClientWrite
在客户端发送数据前, 会调用该函数处理数据,例如追加自定义帧头,帧尾或者解析值到变量等,该函数必须返回处理后的数据。
例如
export async function beforeClientWrite( data ) {
return data;
}
$this.variableGet(name)
获取当前变量值, 例如 $this.variableGet('counter')
。 当变量不存在时将会抛出异常。
请求参数
name
: 变量名称。返回值: 变量值
例如:
export async function init() {
// 获取变量值
let counter = $this.variableGet('counter');
console.log('Counter:', counter);
}
$this.variableSet(name, value)
设置当前变量值, 当变量不存在时将会抛出异常。
请求参数
name
: 变量名称。value
: 变量值。返回值: 无
例如:
export async function init() {
// 设置变量值
$this.variableSet('counter', 1);
}
当服务接收到数据后, 会依次匹配每个规则, 当规则匹配成功时, 会执行对应的响应操作,并且停止匹配。
当规则为任意
时, 会匹配任意数据。 所以可以将任意
规则放在最后, 以确保能够匹配到所有未匹配的数据。
当规则为文本
时, 会以文本方式进行匹配, 如果收到的数据与规则内容相同, 则执行对应的响应操作。
当规则为 通配符
时, 会以通配符方式进行匹配, 如果收到的数据与规则匹配成功, 则执行对应的响应操作。
在通配符中,使用 *
表示任意字符,使用 ?
表示任意单个字符。 如果需要匹配 *
或 ?
字符, 需要使用 \
进行转义。
例如, 规则 01*03
匹配 010203
, 01?03
匹配 0103
。
当规则为HEX
时, 会以HEX方式进行匹配, 如果收到的数据与规则内容相同, 则执行对应的响应操作。
当规则为正则表达式
时, 会以正则表达式进行匹配, 如果接收到的数据与规则匹配成功, 则执行对应的响应操作。
如果正则表达式中存在分组, 则分组数据将会被作为上下文数据用于响应操作。
例如, 正则表达式(?<temp>\d+),(?<level>\d+)
匹配123,456
时,
temp
的值为123
, level
的值为456
。
则在响应规则模板中可以使用 {{temp}}
和 {{level}}
来引用上下文数据。
当规则为HEX匹配
时, 会以HEX方式进行匹配, 如果接收到的数据与规则匹配成功, 则执行对应的响应操作。
如果表达式中存在变量解析, 则变量将会被解析为上下文数据用于响应操作。
例如, 表达式01 02 @U8<num> 04
匹配01 02 03 04
时, num
的值为数值3
。
则在响应规则模板中可以使用 {{num}}
来引用上下文数据。
当匹配规则为JSON
时, 会将请求数据解析为JSON对象后进行匹配, 如果接收到的数据与规则匹配成功, 则执行对应的响应操作。
并且收到的数据会被解析为JSON对象, 以便于后续的响应操作。
例如, 规则 $request.name === 'test'
匹配 {"name":"test"}
时, 则执行对应的响应操作。
其中 $request
表示整个JSON对象, $request.name
表示JSON对象中的 name
属性。
当匹配成功时, 会将匹配到的JSON对象作为上下文数据用于响应操作,
例如在响应规则模板中可以使用 {{$request.name}}
来引用上下文数据。
当规则为表达式
时, 会以表达式方式进行匹配, 如果接收到的数据与规则匹配成功, 则执行对应的响应操作。
其中,表达式可以调用 MOCK服务中脚本到处的函数, 例如在脚本中导出函数 test
:
export function test(name) {
return name === 'test';
}
则可以在匹配规则中使用 test('test')
进行匹配, 如果表达式返回 true
, 则执行对应的响应操作。
片段用于保存一些常用的传输内容,以便在需要时重复使用。 片段支持文本和HEX两种格式, 支持批量发送。
启用
: 配置是否启用该片段, 当片段被禁用时, 批量发送时不会发送该片段。名称
: 片段名称, 用于标识片段。格式
: 配置片段的格式, 支持文本和HEX两种格式。内容
: 配置片段的内容, 根据不同的格式填写不同的内容。延时
: 配置片段发送的延时时间, 单位毫秒。手动内容发送用于发送自定义内容。 支持文本和HEX两种格式, 支持定时发送。