Как удалить маршалинг JSON строки, содержащей метку порядка байтов UTF-8 (BOM)? - PullRequest
0 голосов
/ 14 февраля 2020

Итак, я вроде уже решил проблему, с которой столкнулся. Это связано с тем, использую ли я кодирование в StreamWriter моего C# клиента, но я хочу знать, как обрабатывать эти дополнительные 3 байта независимо от этого.

Это клиент, написанный на C# и Сервер написан на Go. Почему C#? Позже в облаке появятся приложения Unity. Почему Go? Я просто хотел его использовать. Кроме того, мой серверный сервер Linux и Go легко компилируются.

Проблема заключалась в том, что данные, отправляемые с моего C# клиента, имели 3 дополнительных байта, добавленных к фронту, которые конфликтовали с помощью функции Go Json.Unmarshal, подающей его непосредственно после поступления этих данных на сервер.

Это строка в формате JSON, оставляющая клиента C#
{"channel":0, "data": {"name":"Hasty Wombat","uuid":"e91ccc23-7e80-4189-958e-9b778dce1146","type":"Drone"}}\n

Это байтовый массив до прохождения через потоковую запись, сконфигурированную с UTF8 в клиенте C#.
_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

И когда он попадает на мой 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]

Из моих быстрых исследований эти 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

Функция Json.Unmarshal в Go не любит этот байтовый массив. Сначала мой обходной путь должен был просто отрезать первые 3 байта. Но это вызывает проблемы, когда я начал добавлять Go клиентов, чей вывод TCP не добавляет эти 3 байта.

Очевидный обходной путь - просто не использовать UTF8 в моем StreamWriter на клиенте C#.

// 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);

// 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();
  }
}

Теперь я хочу знать, есть ли в Go что-то, что правильно декодирует байтовый массив UTF8, или что-то, что правильно определяет эти дополнительные байты (или любые дополнительные байты кодирования на самом деле), и дайте мне raw JSON хочет функция Json.Unmarshal. Я пытаюсь сделать настройку Stream Writer универсальной, но пока не уверен, понадобится ли мне что-нибудь в кодировке UTF8 или в чем преимущества.

1 Ответ

5 голосов
/ 14 февраля 2020

UTF-8 имеет четко определенный порядок байтов. Нет такого понятия, как UTF-8 с прямым порядком байтов и UTF-8 с прямым порядком байтов; есть только UTF-8. Это означает, что маркер порядка байтов или спецификация в UTF-8 не имеет смысла. Некоторое программное обеспечение считает это целесообразным: оно помечает файл данных как сохраненный в UTF-8 (против UTF-16-LE или UTF-16-BE, каждый из которых начинается с двух байтов 0xFF и 0xFE, но в любом порядке, если этот файл UTF-16-xx имеет спецификацию). Пока вы соглашаетесь с тем, что такое программное обеспечение является неправильным, не используйте его или используйте его таким образом, чтобы победить эту первоначальную спецификацию.

Как заметил Джим Б , системы, которые генерируют JSON текст не должен вставлять специфицированную UTF-8 спецификацию (которая представляет собой три байта 0xEF, 0xBB, 0xBF) в начале своего выхода. Однако он может принять и игнорировать спецификацию в начале потока. Чтобы сделать это в Go, проверьте данные входящего потока и удалите исходную спецификацию, если таковая имеется, передавая оставшиеся данные в виде байтов JSON. Но вам, вероятно, лучше сделать так, чтобы ваш код C# генерировал разрешенный вывод, а не воображал ваш код Go, чтобы разрешить запрещенный ввод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...