jQuery AJAX 调用搞乱了字符编码
Posted
技术标签:
【中文标题】jQuery AJAX 调用搞乱了字符编码【英文标题】:jQuery AJAX call messes up character encoding 【发布时间】:2011-03-13 00:42:01 【问题描述】:我有一个输出 JSON 的 servlet。 servlet 的输出编码是 ISO-8859-1。我们 webapp 中的页面也设置为 ISO-8859-1。我会使用 UTF-8,但这不在我的控制范围内;我们必须使用 ISO-8859-1。
当我自己点击 servlet 时,我可以看到已输出的 JSON 数据。字符编码正确,没有一个字符看起来很奇怪。
但是,当我通过 AJAX 调用 servlet 并使用检索到的数据来填充选择框时,我得到 � 代替(似乎)所有有重音的字符(例如,带有重音或重音的 i,分词, 或抑扬顿挫)。当我查看 Firebug 下 Net 选项卡中的响应时,我可以看到文本看起来不错。但是,当我使用该数据填充选择框时,我得到了带问号的菱形。
这些字符都是有效的 ISO-8859-1 字符,所以我不明白为什么它们不能正确显示。
编辑
更多信息。我在jQuery.ajax
中使用GET
并将scriptCharset
设置为ISO-8859-1
。在服务器端,我使用 request.setCharacterEncoding("ISO-8859-1");
将编码明确设置为 ISO-8859-1
编辑
代码示例:
这是我目前拥有的。我添加了scriptCharset: "ISO-8859-1"
无效。
jQuery.ajax(
url: "/countryAndProvinceCodeServlet",
data: data,
dataType: "json",
type: "GET",
success: function(data)
...
,
);
我的 servlet 使用 org.json.JSONObject
并通过 response.getWriter().print(jsonObject.toString());
简单地输出字符串
更新
根据有关 JSON 以及它应该如何成为 UTF-8 的 cmets,我尝试查看是否可以将数据作为文本获取(因此在 jQuery.ajax
中将 dataType
设置为 text
),然后将其评估为 JSON我自己(在 javascript 中)。这似乎也不起作用!当我做console.log
时,我仍然得到时髦的钻石。但是,当我在 Firebug 的 Net 选项卡下查看它时,一切正常:
网络标签:
"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.ajax
得到的东西做console.log(text)
时,我得到以下信息:
"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 对数据做了一些奇怪的事情。
【问题讨论】:
我知道你说这些页面是 ISO-8859-1,但你有没有检查过标题实际上是这样设置的吗? @user384915 - 刚刚更新了我的问题。是的,标题上写着 ISO-8859-1。当我在 Firefox 中查看页面信息时,它显示的是 ISO-8859-1。 @Vivin:另见:***.com/questions/26620/… @Dave 也尝试过。不幸的是,仍然不起作用:( 【参考方案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);
);
【讨论】:
我尝试按照您的建议进行操作,但没有成功。我从编码为 UTF-8 的 servlet 返回 JSON,但这似乎也不起作用。我仍然得到时髦的钻石字符。 感谢您的所有帮助 - 我想通了。它与您在 cmets 中链接到的问题有关(关于明确设置标题)。我假设设置字符编码是一样的,但显然不是!【参考方案2】:php 函数 json_encode 不支持 ISO-8859-1 编码数据。
这篇文章可能会帮助您解决问题:http://www.pabloviquez.com/2009/07/json-iso-8859-1-and-utf-8-%E2%80%93-part2/
【讨论】:
【参考方案3】:RFC 4627 表示 JSON 文本应以 Unicode 编码,无论这意味着什么,json.org 表示所有字符都是“unicode 字符”:
编码
JSON 文本应以 Unicode 编码。默认编码是 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 库可能会解释 RFC 中以各种方式定义 JSON 的 SHALL 子句,例如通过对替换字符进行编码或通过嗅探编码。最好的方法显然是把它带到你无法控制的地方并告诉他们修复它:-)
解决方法
解决此问题的一种方法是创建一个 servlet 过滤器,删除所有与 UTF-8 和 ISO-8859-1 不兼容的字符,并用 JSON 转义符替换它们:
在以下片段中,将 'é' 替换为 '\u00E9' 以便任何有问题的 ISO-8859-1 字符都以相同的 7 位安全传输:
之前: "a" : "éte"
之后: "a" : "\u00E9te"
虽然不那么清晰,但从语义上讲,是一样的,任何好的 JSON 库都应该对它们一视同仁。
【讨论】:
【参考方案4】:我终于明白了。很奇怪!
response.setCharacterEncoding(String)
不起作用 工作(不知道它是否与我的设置或什么有关)。看起来它设置了字符编码,但由于某种原因,jQuery 把它搞砸了。您已像这样显式设置标题:
response.setHeader("Content-Type", "application/json; charset=ISO-8859-1");
感谢大家的帮助!
编辑
我做了一些研究并查看了JavaDocs 并看到了这个:
如果协议提供了这样做的方法,容器必须将用于 servlet 响应编写器的字符编码传达给客户端。在 HTTP 的情况下,字符编码作为文本媒体类型的 Content-Type 标头的一部分进行通信。 请注意,字符编码不能通过 HTTP 标头进行通信如果 servlet 未指定内容类型;但是,它仍然用于对通过 servlet 响应的 writer 编写的文本进行编码。
所以上述方法仍然有效,但您也可以(并且可能应该)这样做:
response.setContentType("application/json");
response.setCharacterEncoding("ISO-8859-1");
【讨论】:
【参考方案5】:在我看来,您收到了一个解析错误,因为响应数据被错误解码,因此包含一些错误的字符。
您可以尝试在 jQuery.ajax 中插入一个附加参数
dataFilter : function ( data, type )
alert(data);
return data;
如果所有非 ASCII 字符('ï'、'é' 等)都有错误但 不同 字符,您可以尝试将错误的编码字符替换为正确的字符,然后从dataFilter
返回正确的编码数据。
【讨论】:
谢谢!我也试过这个:)我仍然得到了被破坏的字符。然而,我发现了真正的问题——编码没有被设置,即使我认为是这样! 我不会用 java 编写程序,所以我可以在服务器端提供帮助。但是,dataFilter
中的所有非 ASCII 字符是否与 � 一样是同一个字符,或者字符不同(在 data
输入参数中)?
是的,我在 dataFilter
中使用了所有非 ascii 字符。实际问题是标题设置不正确。字符被正确编码,但字符集仍然是 UTF8。我必须设置应用程序类型,然后设置字符编码,才能使字符集保持不变。【参考方案6】:
如果您想从数据库中检索数据,您应该将这些写在从 ajax 页面发送请求的页面中的语句下。例如,如果您在页面“A”中编写 HTML 和 AJAX 代码并将变量从 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 数据库中指定表的变量。
【讨论】:
以上是关于jQuery AJAX 调用搞乱了字符编码的主要内容,如果未能解决你的问题,请参考以下文章