Найкращий спосіб зберігати JSON в атрибуті HTML?


112

Мені потрібно помістити об’єкт JSON в атрибут HTML-елемента.

  1. HTML не повинен перевірятись.

    Відповів Квентін: Зберігайте JSON в data-*атрибуті , який є дійсним HTML5.

  2. Об'єкт JSON може бути будь-якого розміру - тобто величезний

    Відповів Майку Морі: Ліміт атрибута HTML - це 65536 символів .

  3. Що робити, якщо JSON містить спеціальні символи? напр {foo: '<"bar/>'}

    Відповів Квентін: Кодуйте рядок JSON перед тим, як вводити його в атрибут відповідно до звичайних умов. Для PHP використовуйте функцію . htmlentities()


EDIT - Приклад рішення з використанням PHP та jQuery

Запис JSON в атрибут HTML:

<?php
    $data = array(
        '1' => 'test',
        'foo' => '<"bar/>'
    );
    $json = json_encode($data);
?>

<a href="#" data-json="<?php echo htmlentities($json, ENT_QUOTES, 'UTF-8'); ?>">CLICK ME</a>

Отримання JSON за допомогою jQuery:

$('a').click(function() {

    // Read the contents of the attribute (returns a string)
    var data = $(this).data('json');

    // Parse the string back into a proper JSON object
    var json = $.parseJSON($(this).data('json'));

    // Object now available
    console.log(json.foo);

});

Ви, ймовірно, повинні пояснити, чому і попросити інше рішення, оскільки я впевнений, що це не найкраще. Можна застосувати атрибути data-something, але я не впевнений, чи можуть вони вмістити "величезну" кількість тексту. Щодо спеціальних символів, ви можете просто закодувати текст (escape () та unescape ()).
Майку Морі

Так межа 65536 символів ( stackoverflow.com/questions/2752457 / ... )
Maiku Морі

1
Btw, якщо ваш атрибут названий data-jsonви повинні використовувати $(this).data('json'), jQuery вказав на цій частині.
Ciantic

Лише зауваження, називати суфікс даних json не потрібно. Якщо ви помістите дійсний json в будь-який data-custom_attribute, він буде добре працювати з jQuery.
Гарет Клаборн

будь ласка, зафіксуйте послідовність дужок)}; =>});
MotsManish

Відповіді:


41

HTML не повинен перевірятись.

Чому ні? Перевірка дійсно проста QA, яка виявляє багато помилок. Використовуйте data-*атрибут HTML 5 .

Об'єкт JSON може бути будь-якого розміру (тобто величезного).

Я не бачив жодної документації щодо обмежень браузера для розмірів атрибутів.

Якщо ви все-таки натрапите на них, то збережіть дані в а <script>. Визначте об'єкт і позначте елемент ids для імен властивостей цього об'єкта.

Що робити, якщо JSON містить спеціальні символи? (наприклад, {test: '<"myString />'})

Просто дотримуйтесь звичайних правил щодо включення недовірених даних у значення атрибутів. Використовуйте &amp;і &quot;(якщо ви вказуєте значення атрибута у подвійні лапки) або &#x27;(якщо ви вказуєте значення атрибута в одинарні лапки).

Однак зауважте, що це не JSON (що вимагає, щоб назви властивостей були рядками, а рядки були обмежені лише подвійними лапками).


5
Отже, ви кажете, що я повинен зробити, htmlentities($json)перш ніж вкласти його в атрибут HTML? Тоді як я розшифрую це, коли хочу прочитати його в jQuery? Тоді як я можу записати його назад, використовуючи jQuery так само, як це було в PHP?
BadHorsie

6
Отже, ви кажете, що я повинен зробити html_encode ($ json), перш ніж вкласти його в атрибут HTML? - якщо ви використовуєте PHP, то це спрацює. Тоді як я розшифрую це, коли хочу прочитати його в jQuery? - Розшифрувати з атрибута? Браузер зробить це, коли він розбере HTML у DOM. Тоді як я можу записати його назад, використовуючи jQuery так само, як це було в PHP? - Ви встановлюєте атрибути вузлів DOM, не генеруючи необроблений HTML, браузер подбає про це.
Квентін

1
На даний момент у мене виникла проблема, коли мій браузер зараз не розшифровує його в Google Chrome, і коли я переходжу до розбору JSON, усі HTML-елементи існують і не працюють.
Бредлі Вестон

Якщо ви помістите його в тег скрипту, вам доведеться уникати його по-різному через особливу обробку тегів сценарію. наприклад, значення з </script> в ньому закінчиться тегом сценарію.
Dobes Vandermeer

16

Залежно від того, куди ви її поклали,

  • В , <div>як ви просили, ви повинні переконатися , що JSON не містить HTML - події , які могли б почати тег, HTML коментар, вбудований доктайпів і т.д. Вам потрібно бігти , по крайней мере <, і &таким чином , що первинний характер НЕ З'являються в послідовності, що уникнула.
  • У <script>елементах вам потрібно переконатися, що JSON не містить кінцевого тегу </script>або граничного текстового межі: <!--або -->.
  • У обробниках подій вам потрібно переконатися, що JSON зберігає своє значення, навіть якщо в ньому є речі, схожі на HTML-сутності та не порушують межі атрибутів ( "або ').

Для перших двох випадків (і для старих парсерів JSON) слід кодувати U + 2028 та U + 2029, оскільки це символи нового рядка в JavaScript, хоча вони дозволені в рядках, незашифрованих в JSON.

Для коректності вам потрібно уникнути \цитування символів JSON і ніколи не погана ідея завжди кодувати NUL.

Якщо HTML може подаватися без кодування вмісту, його слід кодувати, +щоб запобігти атакам UTF-7 .

У будь-якому випадку спрацює наступна таблиця:

  • NUL -> \u0000
  • CR -> \nабо\u000a
  • LF -> \rабо\u000d
  • " -> \u0022
  • & -> \u0026
  • ' -> \u0027
  • + -> \u002b
  • /-> \/або\u002f
  • < -> \u003c
  • > -> \u003e
  • \-> \\або\u005c
  • U + 2028 ->\u2028
  • U + 2029 -> \u2029

Отже, значення рядка JSON для тексту Hello, <World>!з новим рядком в кінці буде "Hello, \u003cWorld\u003e!\r\n".


1
return (input.replace(/([\s"'& + \ / \\ <> \ u2028 \ u2029 \ u0000]) / g, (матч, p1) => {повернення \\u${p1.codePointAt(0).toString(16).padStart(4, 0)}; })); `
Денис Гіффелер

14

Ще один спосіб зробити це - ввести дані json всередину <script>тегу, але не з type="text/javascript", а з type="text/bootstrap"або type="text/json"ввести, щоб уникнути виконання javascript.

Потім у будь-якому місці вашої програми ви можете запитати її таким чином:

function getData(key) {
  try {
    return JSON.parse($('script[type="text/json"]#' + key).text());
  } catch (err) { // if we have not valid json or dont have it
    return null;
  } 
}

На стороні сервера ви можете зробити щось подібне (цей приклад із php та twig ):

<script id="my_model" type="text/json">
  {{ my_model|json_encode()|raw }}
</script>

1
Для JSON використовуйте сценарій типу "application / json". Також приємно мати верхній рівень як об’єкт у довгостроковій перспективі.
OIS

1
Це не відповідає безпосередньо на запитання ОП, але все одно мені було дуже корисно. Дані, які я зберігаю, застосовуються до сторінки в цілому, а не до якогось конкретного елемента, тому атрибут елемента насправді не працює (якщо я не ставлю його як на елемент тіла, який просто здається мені кульгавим, особливо з мого дані можуть бути великими). Збереження його у <script type="application/json" id="MyData"></script>творі ідеально. Потім, використовуючи ActiveWAFL / DblEj, я можу подивитися його з: document.GetData("#MyData").
Еван де ла Крус

2
Ця відповідь містить неправдиву / небезпечну інформацію! Зміна типу сценарію не змінює виявлення тегів </script>. Просто спробуйте:<script type="application/json" id="MyData"> "abc</script><script>alert()</script>" </script>
гіперкнот

12

Інший варіант полягає в тому, щоб base64 кодувати рядок JSON, і якщо вам потрібно використовувати його у вашому JavaScript, декодуйте його за допомогою atob()функції.

var data = JSON.parse(atob(base64EncodedJSON));

Дякуємо за atob. Я ніколи про це не знав!
Іфдіді Оконкво

3
Остерігайтеся - не працює, якщо JSON містить не латинські символи.
Реалексер

5

Ви можете використовувати нокаути,

<p>First name: <strong data-bind="text: firstName" >todo</strong></p>
<p>Last name: <strong data-bind="text: lastName">todo</strong></p>

knockout.js

// This is a simple *viewmodel* - JavaScript that defines the data and behavior of your UI
function AppViewModel() {
    this.firstName = "Jayson";
    this.lastName = "Monterroso";
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Вихід

Ім'я: Джейсон Прізвище: Монтеррозу

Перевірте це: http://learn.knockoutjs.com/


2

Тут нічого фантазії. З PHP дайте рядок JSON пропустити, htmlspecialcharsщоб переконатися, що жодні спеціальні символи не можуть бути інтерпретовані як HTML. З Javascript не потрібне вимкнення; просто встановіть атрибут, і ви готові йти.


2

Для простих об'єктів JSON код нижче працює.

Кодування:

var jsonObject = { numCells: 5, cellWidth: 1242 };
var attributeString = escape(JSON.stringify(jsonObject));

Розшифруйте:

var jsonString = unescape(attributeString);
var jsonObject = JSON.parse(jsonString);

1

Що ви можете зробити , це використовувати CDATA навколо вашого елемента / с , як це

<![CDATA[  <div class='log' mydata='${aL.logData}'>${aL.logMessage}</div>     ]]>  

де mydata - це сирий рядок json. Сподіваюся, що це допоможе вам та іншим.


Як (може) це рішення працює? Що робити, якщо я хочу зберігати щось на зразок ">моїх даних?
Мартін Печка

1
Що робити, якщо рядок містить "]]>"
Dobes Vandermeer

1

Інша думка, яка може бути використана, - це зберігати дані JSON як рядок base64 в атрибуті, а потім використовувати window.atobабо window.btoaвідновити його до корисних даних JSON.

<?php
$json = array("data"=>"Some json data thing");
echo "<div data-json=\"".base64_encode(json_encode($json))."\"></div>";
?>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.