Как правильно кодировать символы URIcomponent, отличные от utf-8, и соответственно декодировать их?

У меня есть букмарклет Javascript, который использует encodeURIcomponent для передачи URL-адреса текущей страницы на серверную сторону, а затем использует urldecode на стороне сервера для возврата символов.

Проблема в том, что когда закодированный символ не в utf-8 (в моем случае это gb2312, но может быть и что-то другое), и когда сервер делает urldecode, декодированный символ становится квадратным. Что, очевидно, не так, как это выглядело до кодирования.

Это букмарклет, ввод может быть любым, поэтому я не могу просто определить «кодировать как gb2312» в js или «декодировать как gb2312» в php-скриптах.

Итак, есть ли правильный способ использования encodeURIcomponent, который передает кодировку символов вместе с содержимым, а затем декодирование может выбрать правильную кодировку для ее декодирования?


person lazycai    schedule 28.04.2012    source источник


Ответы (2)


Для кодировки браузеров, особенно для кодировки GB2312, сначала проверьте следующие документы (на китайском языке).

В вашем случае %C8%B7%B6%A8 фактически генерируется из формы GB2312 '\u786e\u5b9a'. Это обычно происходит в (устаревших?) версиях IE и FF, когда пользователь напрямую вводит китайский символ в строке адреса,
Или вы используете нестандартную ссылку из содержимого страницы, которая вообще не выполняет кодирование IRI в URI, а просто отображает двоичную строку, например '/tag/\xc8\xb7\xb6\xa8' (на douban.com раньше использовалось такое использование для тегов, теперь они используют правильную кодировку URI в UTF8). не совсем уверен, потому что не может воспроизвести в хроме, может быть потестить в FF и IE, часть про дубан правда.

На самом деле, правильный вывод encodeURIComponent должен быть

> encodeURIComponent('%C8%B7%B6%A8')
  "%25C8%25B7%25B6%25A8"

Таким образом, на стороне сервера, когда строка без кавычек содержит байты, отличные от ascii, вам лучше оставить строку как есть, здесь '%C8%B7%B6%A8'.

Кроме того, вы можете проверить на стороне клиента, чтобы снова применить encodeURIComponent к значению, содержащему %XX, где XX больше, чем 0x7F. Я не совсем уверен, соответствует ли это RFC 2396.

写英文好累啊,不过还是要入乡随俗~

person okm    schedule 30.04.2012
comment
хороший источник, посмотрю :) - person lazycai; 02.05.2012

Используйте escape(), а затем переведите символы в цифровую ссылку на символ перед их отправкой на сервер.

Из ссылки на MDN escape():

Шестнадцатеричная форма для символов, чье кодовое значение равно 0xFF или меньше, представляет собой управляющую последовательность из двух цифр: %xx. Для символов с большей кодовой единицей используется четырехзначный формат %uxxxx.

Таким образом, легко преобразовать вывод escape() в числовую ссылку на символ с помощью простого оператора replace():

escape(input_value).replace(/%u([0-9a-fA-F]{4})/g, '&#x$1;');

Или, если ваш серверный язык поддерживает только десятичные числа, используйте:

escape(input_value).replace(/%u([0-9a-fA-F]{4})/g, function(m0, m1) {
                return '&#' + parseInt(m1, 16) + ';';
};

Пример кода на PHP

client.html (кодировка файла: GB2312):

<html>
  <head>
    <meta charset="gb2312">
    <script>
    function processForm(form) {
        console.log('BEFORE:', form.test.value);
        form.test.value = escape(form.test.value).replace(/%u(\w{4})/g, function(m0, m1) {
            return '&#' + parseInt(m1, 16) + ';';
        });
        console.log('AFTER:', form.test.value);
        return true;
    }
    </script>
  </head>
  <body>
    <form method="post" action="server.php" onsubmit="return processForm(this);">
      <input type="text" name="test" value="确定">
      <input type="submit">
    </form>
  </body>
</html>

server.php:

<?php
echo '<script>console.log("', 
     $_REQUEST['test'], ' --> ', 
     mb_decode_numericentity($_REQUEST['test'], array(0x80, 0xffff, 0, 0xffff), 'UTF-8'),
     '");</script>';
?>
person cychoi    schedule 18.11.2014