Flutter: HttpClient post contentLength - исключение - PullRequest
0 голосов
/ 29 апреля 2018

Очень странно ...

Чтобы отправить некоторые данные JSON на мой сервер, я определяю contentLength по длине закодированных в JSON данных, но затем получаю исключение, которое говорит: « Размер содержимого превышает указанный contentLength ». Разница составляет 1 байт.

Вот исходный код:

Future<Map> ajaxPost(String serviceName, Map data) async {
  var responseBody = json.decode('{"data": "", "status": "NOK"}');
  try {
    var httpClient = new HttpClient();
    var uri = mid.serverHttps ? new Uri.https(mid.serverUrl, _serverApi + serviceName)
                              : new Uri.http(mid.serverUrl, _serverApi + serviceName);
    var request = await httpClient.postUrl(uri);
    var body = json.encode(data);

    request.headers
      ..add('X-mobile-uuid', await _getDeviceIdentity())
      ..add('X-mobile-token', await mid.getMobileToken());

    request.headers.contentLength = body.length;
    request.headers.set('Content-Type', 'application/json; charset=utf-8');
    request.write(body);

    var response = await request.close();
    if (response.statusCode == 200){
      responseBody = json.decode(await response.transform(utf8.decoder).join());

      //
      // If we receive a new token, let's save it
      //
      if (responseBody["status"] == "TOKEN"){
        await mid.setMobileToken(responseBody["data"]);

        // Let's change the status to "OK", to make it easier to handle
        responseBody["status"] = "OK";
      }
    }
  } catch(e){
    // An error was received
    throw new Exception("AJAX ERROR");
  }
  return responseBody;
}

В другое время все работает нормально ...

Что-то не так с этим кодом?

Большое спасибо за вашу помощь.

РЕДАКТИРОВАНИЕ С РЕШЕНИЕМ :

Большое спасибо за вашу помощь. Простой факт использования utf8.encode(json.encode(data)) не работал полностью. Итак, я обратился к библиотеке http , и теперь она работает как шарм. Код еще легче!

Вот новая версия кода:

Future<Map> ajaxPut(String serviceName, Map data) async {
  var responseBody = json.decode('{"data": "", "status": "NOK"}');
  try {
    var response = await http.put(mid.urlBase + '/$_serverApi$serviceName',
        body: json.encode(data),
        headers: {
          'X-mobile-uuid': await _getDeviceIdentity(),
          'X-mobile-token': await mid.getMobileToken(),
          'Content-Type': 'application/json; charset=utf-8'
        });

    if (response.statusCode == 200) {
      responseBody = json.decode(response.body);

      //
      // If we receive a new token, let's save it
      //
      if (responseBody["status"] == "TOKEN") {
        await mid.setMobileToken(responseBody["data"]);

        // Let's change the status to "OK", to make it easier to handle
        responseBody["status"] = "OK";
      }
    }
  } catch (e) {
    // An error was received
    throw new Exception("AJAX ERROR");
  }
  return responseBody;
}

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Гюнтер прав. Content-Length должен быть длиной байтового массива после кодирования из строки в байты в любой кодировке, которую требует ваш сервер.

Существует пакет под названием http , который обеспечивает API чуть более высокого уровня (он использует http-клиент dart.io под капотом), который заботится о кодировании тела и длины сообщения. Например, когда вам нужно отправить форму application/x-www-form-urlencoded, она даже возьмет карту и выполнит всю кодировку за вас (вам все равно нужно кодировать в json самостоятельно). В равной степени счастлив отправить просто String или List<int>. Вот пример:

  Map<String, String> body = {
    'name': 'doodle',
    'color': 'blue',
    'teamJson': json.encode({
      'homeTeam': {'team': 'Team A'},
      'awayTeam': {'team': 'Team B'},
    }),
  };

  Response r = await post(
    url,
    body: body,
  );
0 голосов
/ 21 мая 2019

У меня это работает с

req.headers.contentLength = utf8.encode(body).length;

Из косвенной подсказки Utf8Codec документации, в которой говорится

декодирование (список codeUnits, {bool allowMalformed}) → строка

Декодирует кодовые единицы UTF-8 (список 8-разрядных целых чисел без знака) в соответствующую строку.

Это означает, что utf8.encode() возвращает codeUnits, что на самом деле означает List<uint8>.

Кодирование полезной нагрузки String теоретически вернет список, длина которого равна длине полезной нагрузки в байтах.

Таким образом, использование httpClient означает всегда измерять длину полезной нагрузки в байтах , а не длину строки, которая может отличаться.

0 голосов
/ 29 апреля 2018

Кажется, ваша строка содержит многобайтовые символы. UTF8-кодирует строку, чтобы получить правильную длину:

var body = utf8.encode(json.encode(data));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...