вызов jQuery AJAX портит кодировку символов

у меня есть сервлет, который выводит JSON. Выходная кодировка сервлета-ISO-8859-1. Страницы в нашем веб-приложении также установлены на ISO-8859-1. Я бы использовал UTF-8, но это вне моего контроля; мы должны использовать ISO-8859-1.

когда я нажимаю сервлет сам по себе, я вижу данные JSON, которые были выведены. Кодировка символов правильная, и ни один из символов не выглядит странно.

однако, когда я вызываю сервлет через AJAX и использую данные, полученные для заполняя поле выбора, я получаю � вместо (кажется) всех символов, которые имеют акценты (например, I с серьезным или острым акцентом, диерезисом или окружностью). Когда я смотрю на ответ на вкладке Net под Firebug, я вижу, что текст выглядит нормально. Однако, когда я использую эти данные для заполнения поля выбора, я получаю алмаз с вопросительным знаком.

эти символы являются действительными символами ISO-8859-1, и поэтому я не понимаю, почему они не появляются правильно.

редактировать

дополнительная информация. Я использую GET на jQuery.ajax и я scriptCharset to ISO-8859-1. На стороне сервера я явно установил кодировку ISO-8859-1 с помощью request.setCharacterEncoding("ISO-8859-1");

редактировать

примеры кода:

это то, что у меня есть в настоящее время. Я добавил scriptCharset: "ISO-8859-1" нет эффекта.

        jQuery.ajax({
            url: "/countryAndProvinceCodeServlet",
            data: data,
            dataType: "json",
            type: "GET",
            success: function(data) {
               ...
            },
        });

мой сервлет использует org.json.JSONObject и просто выводит строку, делая response.getWriter().print(jsonObject.toString());

обновление

в комментариях о JSON и как это должно быть UTF-8, я попытался увидеть, могу ли я захватить данные как текст (так что установите dataType to text на jQuery.ajax), а затем оценить его как JSON себя (в Javascript). Это тоже не работает! Когда я делаю console.log, я все еще получаю фанки алмазов. Однако, когда я смотрю на него под вкладкой Net в Firebug, все выглядит нормально:

Net tab:

{"error":false,
 "provinces":{"DZ-01":"Adrar",
              "DZ-16":"Alger",
              "DZ-23":"Annaba",
              "DZ-44":"Aïn Defla",
              "DZ-46":"Aïn Témouchent",
              "DZ-05":"Batna",
              "DZ-07":"Biskra",
              "DZ-09":"Blida",
              "DZ-34":"Bordj Bou Arréridj",
              "DZ-10":"Bouira",
              "DZ-35":"Boumerdès",
              "DZ-08":"Béchar",
              "DZ-06":"Béjaïa",
              "DZ-02":"Chlef",
              "DZ-25":"Constantine",
              "DZ-17":"Djelfa",
              "DZ-32":"El Bayadh",
              "DZ-39":"El Oued",
              "DZ-36":"El Tarf",
              "DZ-47":"Ghardaïa",
              "DZ-24":"Guelma",
              "DZ-33":"Illizi",
              "DZ-18":"Jijel",
              "DZ-40":"Khenchela",
              "DZ-03":"Laghouat",
              "DZ-29":"Mascara",
              "DZ-43":"Mila",
              "DZ-27":"Mostaganem",
              "DZ-28":"Msila",
              "DZ-26":"Médéa",
              "DZ-45":"Naama",
              "DZ-31":"Oran",
              "DZ-30":"Ouargla",
              "DZ-04":"Oum el Bouaghi",
              "DZ-48":"Relizane",
              "DZ-20":"Saïda",
              "DZ-22":"Sidi Bel Abbès",
              "DZ-21":"Skikda",
              "DZ-41":"Souk Ahras",
              "DZ-19":"Sétif",
              "DZ-11":"Tamanghasset",
              "DZ-14":"Tiaret",
              "DZ-37":"Tindouf",
              "DZ-42":"Tipaza",
              "DZ-38":"Tissemsilt",
              "DZ-15":"Tizi Ouzou",
              "DZ-13":"Tlemcen",
              "DZ-12":"Tébessa"}}

но когда я это делаю console.log(text) С тем, что я получаю от jQuery.ajax, Я получаю следующее:

{"error":false,
 "provinces":{"DZ-01":"Adrar",
              "DZ-16":"Alger",
              "DZ-23":"Annaba",
              "DZ-44":"A�n Defla",
              "DZ-46":"A�n T�mouchent",
              "DZ-05":"Batna",
              "DZ-07":"Biskra",
              "DZ-09":"Blida",
              "DZ-34":"Bordj Bou Arr�ridj",
              "DZ-10":"Bouira",
              "DZ-35":"Boumerd�s",
              "DZ-08":"B�char",
              "DZ-06":"B�ja�a",
              "DZ-02":"Chlef",
              "DZ-25":"Constantine",
              "DZ-17":"Djelfa",
              "DZ-32":"El Bayadh",
              "DZ-39":"El Oued",
              "DZ-36":"El Tarf",
              "DZ-47":"Gharda�a",
              "DZ-24":"Guelma",
              "DZ-33":"Illizi",
              "DZ-18":"Jijel",
              "DZ-40":"Khenchela",
              "DZ-03":"Laghouat",
              "DZ-29":"Mascara",
              "DZ-43":"Mila",
              "DZ-27":"Mostaganem",
              "DZ-28":"Msila",
              "DZ-26":"M�d�a",
              "DZ-45":"Naama",
              "DZ-31":"Oran",
              "DZ-30":"Ouargla",
              "DZ-04":"Oum el Bouaghi",
              "DZ-48":"Relizane",
              "DZ-20":"Sa�da",
              "DZ-22":"Sidi Bel Abb�s",
              "DZ-21":"Skikda",
              "DZ-41":"Souk Ahras",
              "DZ-19":"S�tif",
              "DZ-11":"Tamanghasset",
              "DZ-14":"Tiaret",
              "DZ-37":"Tindouf",
              "DZ-42":"Tipaza",
              "DZ-38":"Tissemsilt",
              "DZ-15":"Tizi Ouzou",
              "DZ-13":"Tlemcen",
              "DZ-12":"T�bessa"}}

мне кажется, что jQuery делает что-то странное с данными.

6 ответов


я, наконец, понял. Это довольно странно!

response.setCharacterEncoding(String) тут не работа (не знаю, связано ли это с моей настройкой или что). Похоже, он устанавливает кодировку символов, но по какой-то причине jQuery все портит. У вас есть явно установить заголовки так:

response.setHeader("Content-Type", "application/json; charset=ISO-8859-1");

Спасибо за помощь, всем!

редактировать

Я сделал некоторые исследования и проверили JavaDocs и увидел это:

контейнеры должны передавать кодировку символов, используемую для записи ответа сервлета клиенту, если протокол предоставляет способ сделать это. В случае HTTP кодировка символов передается как часть заголовка Content-Type для типов текстовых носителей. обратите внимание, что кодировка символов не может передаваться через HTTP-заголовки если сервлет не указывает тип контента; однако он все еще используется для кодирования текст, написанный через writer ответа сервлета.

Так выше все еще работает, но вы также можете (и вероятно должны) сделать это:

response.setContentType("application/json");
response.setCharacterEncoding("ISO-8859-1"); 

можете ли вы использовать UTF-8 вместо этого?

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

в PHP вы можете кодировать данные JSON как UTF-8:

/**
 * Applies a UTF-8 encoding conversion for text.
 */
function utf8_enc( $rows ) {
  $encoded = array();

  foreach( $rows as $row ) {
    $temp = array();

    foreach( $row as $name => $value ) {
      $temp[ $name ] = $value = mb_convert_encoding( $value, 'auto', 'UTF-8' );
    }

    array_push( $encoded, $temp );
  }

  return $encoded;
}

function db_json( $query ) {
  echo json_encode( utf8_enc( db_fetch_all( db_query( $query ) ) ) );
}

Я видел некоторые странные результаты, используя набор символов с акцентом ISO-8859-1. Я перешел на UTF-8 и проблемы с кодировкой исчезли.

для чего это стоит, я закодировался getJSON следующим образом:

  $.getJSON( HOST + 'cat.dhtml', function( data ) {
    var h = '';
    var len = data.length;

    for( var i = 0; i < len; i++ ) {
      h += '<option value="' + data[i].id + '">' + data[i].name + '</option>';
      categories[ data[i].id ] = data[i];
    }

    $('#category').html(h);
  });

мне кажется, вы получаете ошибку разбора, потому что данные ответа неправильно декодированы и поэтому содержат неправильные символы.

вы можете попробовать вставить в jQuery.ajax дополнительный параметр

dataFilter : function ( data, type ) {
    alert(data);
    return data;
}

Если вы ошибаетесь, но разные символы для всех символов, отличных от ASCII ("ï", " é " и т. д.), Вы можете попытаться заменить неправильные закодированные символы на правильные символы и вернуть правильные закодированные данные из dataFilter.


RFC 4627 заявляет, что текст JSON должен быть закодирован в Unicode, что бы это ни значило, и json.org указывает, что все символы являются "символами Юникода":

  • кодирование

    текст JSON должен быть закодирован в Юникоде. Кодировку по умолчанию UTF-8.

    Так как первые два символа текста JSON всегда будут ASCII символы [RFC0020], можно определить, является ли октет поток UTF-8, UTF-16 (BE или LE), или UTF-32 (BE или LE), посмотрев на рисунке нулей в первых четырех октетах.

       00 00 00 xx  UTF-32BE
       00 xx 00 xx  UTF-16BE
       xx 00 00 00  UTF-32LE
       xx 00 xx 00  UTF-16LE
       xx xx xx xx  UTF-8
    

поэтому, если вы передаете JSON и говорите, что это ISO-8859-1, тогда разные библиотеки JSON могут интерпретировать предложение SHALL из RFC, которое определяет JSON различными способами, например, кодируя символ замены или нюхая кодировку. Лучший способ, если очевидно, чтобы принять это к тому, что находится вне вашего контроля и сказать им, чтобы исправить это :-)

решения

один из способов обойти это-создать фильтр сервлетов, который удаляет все символы, несовместимые с UTF-8 и ISO-8859-1, и заменяет их на JSON escapes:

в следующем фрагменте замените " é " на "\u00E9", чтобы любой оскорбительный символ ISO-8859-1 безопасно транспортировался в 7-битах, которые идентичны:

перед: { "a" : "éte" }

после: { "a" : "\u00E9te" }

Это не так разборчиво, но семантически говоря, это то же самое, и любая хорошая библиотека JSON должна относиться к ним одинаково.


функция php json_encode не поддерживает кодированные данные ISO-8859-1.

эта статья может помочь вам с вашей проблемой: http://www.pabloviquez.com/2009/07/json-iso-8859-1-and-utf-8-%E2%80%93-part2/


Если вы хотите получить данные из базы данных, вы должны написать их под предложениями на странице, которая отправляет запрос со страницы ajax. Например, если вы пишете код HTML и AJAX на странице " A "и отправляете переменную из кода java на страницу" B", напишите эти коды на странице"B".
не забывайте, что ваша база данных должна быть в режиме unicode, например "utf8_general_ci".

mysqli_query ($conn,"set character_set_client='utf8'");
mysqli_query ($conn,"set character_set_results='utf8'");
mysqli_query ($conn,"set collation_connection='utf8_general_ci'");
mysqli_query($conn,"set collation_connection='utf8_persian_ci'");
mysqli_set_charset($conn,"set character_set_results='utf8'") ;
mysqli_set_charset($conn,"set collation_connection='utf8_general_ci'") ;

; Я написал это предложение для персидского языка, вы можете изменить его. $conn - это переменная для подключения к указанная таблица в базе данных MySQL.