Персональный блог Александра Мокрова

О работе и отдыхе

Грабельки: Google Chrome и JSON через jQuery AJAX

Грабли google chrome
Кто бы мог ожидать, что около часа экспериментов (включая написание минималистичного прототипа) займут заботливо разложенные разработчиками jquery грабельки ;)

Поиск по инету результатов не дал. Поэтому спешу поделиться.

Сразу скажу, проблема оказалась в знаках табуляции в JSON.

А теперь подробнее…

Итак, имеем минимальный прототип, работающий во всех браузерах, кроме гуглохрома.
index.php:

<?	header("Content-type: text/html; charset=utf-8");?>
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"
  src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
   $('#do_btn').click(function() {
   $.ajaxSetup({cache: false});
   $.ajax({
     method: 'post',
     url: 'json.php',
     data: 'ajax=1',
     dataType: 'json',
     beforeSend: (function() {
       $('#status').html('Processing...');
     }),
     complete: (function() {
       $('#status').html('Complete');
     }),
     success: (function(data) {
       $('#result').html(data.newhtml);
     }),
     error: (function(xmlhttp, textStatus, errorThrown) {
       $('#error').append('AJAX error: [' + xmlhttp.status + '] ' +
         xmlhttp.statusText + '; textStatus=' + textStatus +
         '; errorThrown=' + errorThrown + '<hr/>');
     })
   });

   return false;
 });
});
</script>
</head><body>
<a href="#" id="do_btn">[ DO ]</a>
<br/><br/>
Status:
<div id="status">NONE</div>
<br/><br/>
Result:
<div id="result">NONE</div>
<br/><br/>
ERROR:
<div id="error">NONE</div>
</body></html>

И json.php

{"newhtml":"	html data\n"}

Перед html дата – символ табуляции (\x09)

Во всех современных браузерах получаем то что и ожидалось: в <div id=»#result»> текст «html data». Но в хроме…
ERROR:
AJAX error: [200] OK; textStatus=parsererror; errorThrown=SyntaxError: Unexpected token ILLEGAL

При этом если слегка видоизменить пример, поменяв тип возвращаемого контента на text и скормив его eval’у, все работает. То есть json корректен.
Это же подтверждается json.org:

char
any-Unicode-character-
except-»-or-\-or-
control-character

\\
\/
\b
\f
\n
\r
\t
\u four-hex-digits

То есть в JSON строковых данных не допускается лишь символы \ и «. Табуляция допускается.

После того как проблема была продиагностирована, пришло и решение: замена символа табуляции (\x09) на \t (не путать с литералом javascript/php/C++! Нужно чтобы было именно 2 символа \ и t).

4 Комментариев

4 Комментариев

  1. point Июнь 30th, 2010 07:15

    А по-моему всё верно. Читаем стандарт:

    http://www.ietf.org/rfc/rfc4627.txt

    В частности Page 4.

    string = quotation-mark *char quotation-mark

    char = unescaped /
    escape (
    %x22 / ; » quotation mark U+0022
    %x5C / ; \ reverse solidus U+005C
    %x2F / ; / solidus U+002F
    %x62 / ; b backspace U+0008
    %x66 / ; f form feed U+000C
    %x6E / ; n line feed U+000A
    %x72 / ; r carriage return U+000D
    %x74 / ; t tab U+0009
    %x75 4HEXDIG ) ; uXXXX U+XXXX

    escape = %x5C ; \

    quotation-mark = %x22 ; »

    unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

    Важное в «unescaped = %x20-21 / %x23-5B / %x5D-10FFFF»

  2. point Июнь 30th, 2010 07:16

    Вдогонку, похоже serializer тебе неверное отдал. Или это собиралось ручками ?

  3. Александр Мокров Июнь 30th, 2010 12:04

    Вдогонку, похоже serializer тебе неверное отдал. Или это собиралось ручками ?

    Джейсон-сериализатор мой собственный. А в приведенном минималистичном тестовом примере – вообще готовая строка ;)

    По поводу RFC – таки действительно, судя по всему, я неправ :)

    All Unicode characters may be placed within the
    quotation marks except for the characters that must be escaped:
    quotation mark, reverse solidus, and the control characters (U+0000 through U+001F).

  4. Александр Мокров Июнь 30th, 2010 12:06

    Но тем не менее, факт, что если сделать тип text и потом

    eval("var jsondata=" + data);

    все корректно парсится с символами табуляции в строке и в jsondata.newhtml получаем нужное :)

    … во всех браузерах, включая хром.

Оставить комментарий