我正在使用node ws library(在Ubuntu 16.04上为节点10.8.0)连接到外部websocket api。我有一个侦听器,它仅解析json并将其传递给回调:
this.ws.on('message', (rawdata) => {
let data = null;
try {
data = JSON.parse(rawdata);
} catch (e) {
console.log('Failed parsing the following string as json: ' + rawdata);
return;
}
mycallback(data);
});
我现在收到rawData
如下的错误(我格式化并删除了不相关的内容):
�~A
{
"id": 1,
etc..
}�~�
{
"id": 2,
etc..
然后我想知道;这些字符是什么?看到结构,我最初认为第一个怪异符号必须是数组([
)的开括号,而第二个是逗号(,
),以便创建对象数组。
然后我通过在文件遇到JSON解析错误时将rawdata
写入文件来进一步研究该问题。在一个小时左右的时间内,它已保存了大约1500个这些错误文件,这意味着很多。我在终端中cat
$string = "It is test string for performance";
// VERSION 1
$time_start = microtime(true);
$explode = explode(' ', $string);
foreach ($explode as $s) {
echo $s . "<br />";
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start)/60;
echo '<b>Total Execution Time:</b> '.$execution_time.' Mins <br />';
// VERSION 2
$time_start2 = microtime(true);
foreach (explode(' ', $string) as $s) {
echo $s . "<br />";
}
$time_end2 = microtime(true);
$execution_time2 = ($time_end2 - $time_start2)/60;
echo '<b>Total Execution Time 2:</b> '.$execution_time2.' Mins <br />';
存放了其中的两个文件,并在下面上传了一个示例:
一些有趣的地方:
我对websocket的经验不是很丰富,但是可能是我的websocket以某种方式接收了将它们连接在一起的消息流,这些消息流带有这些奇怪的符号作为分隔符,然后随机切断了最后一条消息吗?也许是因为我不断收到非常快速的消息?
还是由于服务器端错误(或功能)而将那些单独的消息组合在一起?
有人知道这里发生了什么吗?欢迎所有提示!
[编辑]
@bendataclear建议将其解释为utf8。我照做了,然后粘贴了以下结果的屏幕截图。第一个打印照原样,第二个打印解释为utf8。对我来说,这看起来并不像什么。我当然可以转换为utf8,然后按这些字符分开。尽管最后一条消息总是被截断,但这至少会使某些消息可读。但是仍然有其他想法。
答案 0 :(得分:4)
我的假设是您仅使用英语/ ASCII字符,并且某些内容可能会使流混乱。 (注意:我假设),没有特殊字符,如果是这样,那么我建议您将整个json字符串传递给此函数:
function cleanString(input) {
var output = "";
for (var i=0; i<input.length; i++) {
if (input.charCodeAt(i) <= 127) {
output += input.charAt(i);
}
}
console.log(output);
}
//example
cleanString("�~�")
您可以引用How to remove invalid UTF-8 characters from a JavaScript string?
编辑
摘自Internet Engineering Task Force (IETF)的一篇文章
发送文本数据时出现常见的安全问题 使用错误的编码。该协议指定带有 文本数据类型(与Binary或其他类型相反)包含UTF-8- 编码数据。虽然长度仍然指示和 实现此协议的应用程序应使用长度来 确定帧实际结束的位置,并以不正确的方式发送数据
“有效载荷数据”是编码为UTF-8的文本数据。请注意,特定的文本框架可能包括部分UTF-8序列。但是,整个消息必须包含有效的UTF-8。按照 UTF-8编码数据中的处理错误中的说明处理重组邮件中无效的UTF-8,该状态指出当端点将字节流解释为UTF-8时,却发现字节流实际上不是有效的UTF-8流,则端点必须_使WebSocket Connection_失败。此规则在打开握手期间和后续数据交换期间均适用。
我真的相信您的错误(或功能)是来自服务器端的,它结合了您的各个消息,因此我建议采用一种逻辑,以确保您的所有字符必须都可以转换首先将字符编码为UTF-8,从Unicode转换为ASCII。并且您可能还想安装npm install --save-optional utf-8-validate
来有效地检查邮件是否包含规范要求的有效UTF-8。
您可能还希望通过if
条件来帮助您进行一些检查;
this.ws.on('message', (rawdata) => {
if (message.type === 'utf8') { // accept only text
}
我希望这会有所帮助。
答案 1 :(得分:0)
这些字符被称为“ REPLACEMENT CHARACTER”-用于替换未知,无法识别或无法表示的字符。
发件人:https://en.wikipedia.org/wiki/Specials_(Unicode_block)
替换字符(通常是带有白色问号的黑色菱形或一个空的方框),是Unicode标准中Specials表中代码点U + FFFD处的符号。当系统无法将数据流呈现为正确的符号时,它用于指示问题。通常会在数据无效且不匹配任何字符时看到
检查section 8 of the WebSocket protocol Error Handling:
8.1。从服务器处理UTF-8中的错误
当客户端将字节流解释为UTF-8但发现该字节流实际上不是有效的UTF-8流时,则无效的UTF-8序列的任何字节或字节序列必须为解释为U + FFFD替换字符。
8.2。从客户端处理UTF-8中的错误
当服务器将字节流解释为UTF-8但发现该字节流实际上不是有效的UTF-8流时,则行为未定义。服务器可以关闭连接,将无效的字节序列转换为U + FFFD替换字符,逐字存储数据,或执行特定于应用程序的处理。 WebSocket协议上的子协议可能会定义服务器的特定行为。
取决于使用的实现或库如何处理此问题,例如,来自本帖子Implementing Web Socket servers with Node.js:
socket.ondata = function(d, start, end) {
//var data = d.toString('utf8', start, end);
var original_data = d.toString('utf8', start, end);
var data = original_data.split('\ufffd')[0].slice(1);
if (data == "kill") {
socket.end();
} else {
sys.puts(data);
socket.write("\u0000", "binary");
socket.write(data, "utf8");
socket.write("\uffff", "binary");
}
};
在这种情况下,如果找到�
,它将这样做:
var data = original_data.split('\ufffd')[0].slice(1);
if (data == "kill") {
socket.end();
}
您可以做的另一件事是,将OpenSSL and Breaking UTF-8 Change (fixed in Node v0.8.27 and v0.10.29)上的内容更新为最新的节点:
从这些发行版开始,如果您尝试传递带有不匹配代理对的字符串,则Node将用未知的Unicode字符(U + FFFD)替换该字符。为了保留旧的行为,请将环境变量NODE_INVALID_UTF8设置为任何值(甚至什么也没有)。如果根本没有环境变量,它将恢复为旧的行为。
答案 2 :(得分:0)
答案 3 :(得分:0)
您遇到的问题是,一方发送的JSON与另一方发送的编码不同。
尝试使用以下代码解决此问题:
const { StringDecoder } = require('string_decoder');
this.ws.on('message', (rawdata) => {
const decoder = new StringDecoder('utf8');
const buffer = new Buffer(rawdata);
console.log(decoder.write(buffer));
});
或使用utf16
:
const { StringDecoder } = require('string_decoder');
this.ws.on('message', (rawdata) => {
const decoder = new StringDecoder('utf16');
const buffer = new Buffer(rawdata);
console.log(decoder.write(buffer));
});