Наиболее безопасный javascript метод JSON Inline

Я использую varnish+esi для возврата внешнего содержимого json из RESTFul API. Этот метод позволяет мне управлять запросами и обновлять данные без использования ресурсов веб-сервера для каждого запроса.

например:

<head>
.... 
<script> 
 var data = <esi:include src='apiurl/data'>;
</script>
...

После включения ESI лак вернет:

 var data = {attr:1, attr2:'martin'};

Это работает нормально, но если API возвращает ошибку, этот метод сгенерирует ошибку разбора.

var data = <html><head><script>...api js here...</script></head><body><h1 ... api html ....

Я решил эту проблему, используя скрытый div для анализа и обнаружения ошибки:

...
<b id=esi-data style=display:none;><esi:include src='apiurl/data'></b>
<script>
  try{
    var data = $.parseJSON($('#esi-data').html());
  }catch{ alert('manage the error here');}
....

Я также пытался использовать скрипт типа text / esi, но браузер отображает HTML внутри тега скрипта (wtf), например:

<script id=esi-data type='text/esi'><esi:include src='apiurl/data'></script>

Вопрос:

Есть ли какая-то причина, чтобы обернуть тег и избежать его разбора браузером?

5 ответов

Решение

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

Подход почти такой же, как то, что вы уже делаете, но вместо использования обычного элемента HTML, такого как div Вы используете iframe,

<iframe id="esi-data" src="about:blank"><esi:include src="apiurl/data"></iframe>
var $iframe = $('#esi-data');

try {
    var data = $.parseJSON($iframe.html());
} catch (e) { ... }

$iframe.remove();
#esi-data { display: none; }

Чем это отличается от вашего решения? Два пути:

  1. Страница данных / ошибок действительно скрыта от ваших посетителей. iframe имеет встроенную модель контента, что означает, что любой контент внутри <iframe>…</iframe> теги полностью заменяются в DOM, но вы все равно можете получить исходный контент, используя innerHTML,

  2. Это действительный HTML5... вроде. В HTML5 разметка внутри элементов iframe обрабатывается как текст. Конечно, вы должны быть в состоянии проанализировать его как фрагмент, и он должен содержать только фразы (и нет script элементы!), но это, по сути, просто обрабатывается как текст валидатором - и браузерами.

  3. Скрипты со страницы ошибок не запускаются. Содержимое анализируется как текст и заменяется в DOM другим документом - никаких шансов для любого script элементы для обработки.

Посмотрите на это в действии. Если вы закомментируете строку, где я удаляю iframe Элемент и осмотреть DOM, вы можете подтвердить, что содержимое HTML заменяется пустым документом. Также обратите внимание, что встроенный script тег никогда не запускается.

Важно: этот подход может все еще сломаться, если третья сторона добавит iframe элемент в их страницу ошибки по какой-то причине. Маловероятно, что это может быть, вы можете пуленепробиваемый подход немного больше, сочетая вашу технику с этим: окружить iframe со скрытым div что вы удалите, когда вы закончите анализ.

Здесь я иду с другой попыткой.

Хотя я полагаю, что у вас уже есть, возможно, лучшее решение для этого, я могу только представить, что вы обойдете его с довольно низкоэффективным методом вызова esi:insert в отдельном окне HTML, а затем получить содержимое, как если бы вы использовали AJAX на сервере. Возможно, похоже на это? Затем проверьте содержимое, которое вы получили, возможно, с помощью json_decode и в случае успеха сгенерируйте ошибку в формате JSON.

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

Я бы честно придерживался вашего текущего решения.

Это довольно сложная проблема без реального элегантного решения, если не без решения вообще

Я спросил вас, был ли это документ HTML(5) или XHTML(5), потому что в последнем случае раздел CDATA можно использовать для переноса содержимого, слегка изменив свое решение на что-то вроде этого:

...
<b id='esi-data' style='display:none;'>
    <![CDATA[ <esi:include src='apiurl/data'> ]]>
</b>
<script>
    try{
        var data = $.parseJSON($('#esi-data').html());
    }catch{ alert('manage the error here');}
....

Конечно, это решение работает, если:

  1. вы используете XHTML5 и
  2. ошибка не содержит раздела CDATA (поскольку вложение раздела CDATA невозможно).

Я не знаю, является ли переключение с одной сериализации на другую вариантом, но я хотел уточнить цель моего вопроса. Надеюсь, это поможет вам:).

<script>var data = 999;</script>

<script>
data = <esi:include src='apiurl/data'>;
</script>

<script>
if(data == 999) alert("there was an error");
</script>

Если есть ошибка и "данные" не являются JSON, то будет выдана ошибка javascript. Следующий блок скрипта подхватит это.

Разве вы не можете просто изменить свой API, чтобы вернуть JSON { "error":"error_code_or_text" } по ошибке? Вы даже можете сделать что-то значимое в своем интерфейсе, чтобы предупредить пользователя об ошибке, если вы сделаете это таким образом.

Другие вопросы по тегам