如何解组包含 UTF-8 字节顺序标记 (BOM) 的 JSON 字符串?

Gho*_*orm 0 c# json tcp utf-8 go

所以,我已经解决了我遇到的问题。这与我是否在 C# 客户端的 StreamWriter 上使用编码有关,但我想知道无论如何如何处理这些额外的 3 个字节。

这是一个用 C# 编写的客户端和一个用 Go 编写的服务器。为什么是 C#?稍后它将有用于云计算的 Unity 应用程序。为什么去?我只是想使用它。另外我的服务器是 Linux 并且 Go 很容易 x-compile。

问题是从我的 C# 客户端发送的数据在前面附加了 3 个额外的字节,这与 Go 的Json.Unmarshal函数在这些数据到达服务器后直接提供它相冲突。

这是离开 C# 客户端的 JSON 格式字符串
{"channel":0, "data": {"name":"Hasty Wombat","uuid":"e91ccc23-7e80-4189-958e-9b778dce1146","type":"Drone"}}\n

这是通过在 C# 客户端中配置为 UTF8 的流编写器之前的字节数组。
_sWriter = new StreamWriter(_tStream, System.Text.Encoding.UTF8, 8192);
长度:108

123 34 99 104 97 110 110 101 108 34 58 48 44 32 34 100 97 116 97 34 58 32 123 34 110 97 109 101 34 58 34 72 97 115 116 121 32 87 111 109 98 97 116 34 44 34 117 117 105 100 34 58 34 101 57 49 99 99 99 50 51 45 55 101 56 48 45 52 49 56 57 45 57 53 56 101 45 57 98 55 55 56 100 99 101 49 49 52 54 34 44 34 116 121 112 101 34 58 34 68 114 111 110 101 34 125 125 10
Run Code Online (Sandbox Code Playgroud)

当它到达我的 Go 服务器时,它看起来像这样:
长度:111

[239 187 191 123 34 99 104 97 110 110 101 108 34 58 48 44 32 34 100 97 116 97 34 58 32 123 34 110 97 109 101 34 58 34 72 97 115 116 121 32 87 111 109 98 97 116 34 44 34 117 117 105 100 34 58 34 50 99 57 49 48 97 99 98 45 53 101 101 102 45 52 98 56 101 45 56 52 50 54 45 54 49 102 100 100 99 99 51 101 51 55 100 34 44 34 116 121 112 101 34 58 34 68 114 111 110 101 34 125 125 10]
Run Code Online (Sandbox Code Playgroud)

根据我的快速研究,在前面添加的 3 个额外字节与有关 UTF8 的字节顺序有关。这很好,但它会干扰我将这个 JSON 字节数组解组到映射中的能力。

func handleRequest (conn net.Conn) {

  for {
    data, err := bufio.NewReader(conn).ReadBytes('\n');
    if err != nil {
      fmt.Println("Client disconnect")
      conn.Close()
      return
    }

    var mappedData map[string]interface{}
    err = json.Unmarshal(data, &mappedData)
    if err != nil {
      fmt.Println("err:", err)
      continue
    }

  // ...
  }
}

err: invalid character 'ï' looking for beginning of value
Run Code Online (Sandbox Code Playgroud)

Json.UnmarshalGo 中的函数不喜欢那个字节数组。起初,我的解决方法是切掉前 3 个字节。但是,当我开始添加其 TCP 输出未添加这 3 个字节的 Go 客户端时,这会导致问题。

显而易见的解决方法是在 C# 客户端上的 StreamWriter 中不使用 UTF8。

// NetworkManager.cs

_tcpconn = new TCPConnection(_ipAddress, _port, OnConnectionFailure);

if (_tcpconn.SetupSocket()) {

var data = "{\"channel\":0, \"data\": {" +
  "\"name\":" + "\"" + _clientName + "\"," +
  "\"uuid\":" + "\"" + _uuid + "\"," +
  "\"type\":" + "\"Drone\"" +
"}}" + "\n";

_tcpconn.WriteSocket(data);

Run Code Online (Sandbox Code Playgroud)
// TCPConnection.cs

public bool SetupSocket () {
  try {
    _socket = new TcpClient(_conHost, _conPort);

    _tStream = _socket.GetStream();
    // _sWriter = new StreamWriter(_tStream, System.Text.Encoding.UTF8, 8192);
    _sWriter = new StreamWriter(_tStream); // Fixed my problem
    _sReader = new StreamReader(_tStream);
  }
  catch (Exception e) {
    throw new Exception("Socket error:" + e.Message);
    return false;
  }
  _socketReady = true;
  return true;
}

public void WriteSocket (string theLine) {
  if (!_socketReady)
  return;

  try {
    _sWriter.Write(theLine);
    _sWriter.Flush();
  }
  catch {
    _socketReady = false;
    _onConnectionFailure();
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我想知道 Go 是否有正确解码 UTF8 字节数组或正确检测这些额外字节(或任何额外的编码字节)的东西,并给我Json.Unmarshal函数想要的原始 JSON 。我试图让我的 Stream Writer 设置变得通用,但我不确定我是否需要一些编码的 UTF8 或者有什么优点。

tor*_*rek 5

UTF-8 具有明确定义的字节顺序。没有大端 UTF-8 与小端 UTF-8 之类的东西;只有 UTF-8。这意味着UTF-8中的字节顺序标记或 BOM 毫无意义。一些软件认为这很有意义:它将数据文件标记为以 UTF-8 存储(与 UTF-16-LE 或 UTF-16-BE 相比,每个都以两个字节 0xFF 和 0xFE 开头,但顺序不一,如果该 UTF-16-xx 文件有 BOM)。只要您同意此类软件是错误的,就不要使用它,或者以破坏初始 BOM 的方式使用它。

正如Jim B 指出的那样,生成 JSON 文本的系统不得在其输出的前面嵌入一个 UTF-8 化的 BOM(它以三个字节 0xEF、0xBB、0xBF 的形式出现)。但是,它可以在流开始时接受和忽略 BOM。要在 Go 中执行此操作,请检查传入的流数据并删除初始 BOM(如果存在),将其余数据作为 JSON 字节传递。但是你最好让你的 C# 代码生成允许的输出,而不是幻想你的 G​​o 代码来允许禁止的输入。