Весной 2021 года я присматривался к свободным вакансиям. Мое внимание привлекла вакансия удаленного старшего веб-инженера в Oracle. После отправки резюме я получил несколько тестовых заданий на выбор. Пройдя немного дальше, мне удалось завершить его и получить предложение о работе.

Особенно интересным тестовым заданием было реализовать четыре способа получения данных на веб-странице из бэкенда без использования какого-либо AJAX и его XMLHttpRequestObject. Давайте рассмотрим эти четыре идеи.

Инъекция IFrame

Первый — создать элемент iframe на странице. Теги iframe позволяют открывать новую веб-страницу внутри существующей. На этой странице мы можем найти данные, которые нам нужно получить с сервера. DOM содержит событие для элемента iframe, позволяющее прочитать его содержимое через свойство textContent.

Код выглядит следующим образом:

    let iframeEl = document.createElement("iframe");
    iframeEl.style.display = "none";
    iframeEl.setAttribute("src", "/iframe-data.txt");

    let getContent = () => 
                iframeEl.contentWindow.document.body.textContent;

    iframeEl.onload = () => 
                console.log('Iframe tag injection: ' + getContent());

    document.body.appendChild(iframeEl);

Внедрение тега скрипта

Следующим шагом является добавление дополнительного тега сценария. Тег используется для запуска кода JavaScript из внешних файлов. Таким образом, внутри этого файла сценария мы можем найти обычный код JS с объектом JSON и известной переменной, доступ к которой осуществляется после события загрузки. Вот код:

    let srcTag = document.createElement("script");
    srcTag.setAttribute("src", " /data.txt");

    srcTag.onload = () => 
                console.log("Script tag injection: " + dataList.sample);

    document.body.appendChild(srcTag);

где data.txt содержит

let dataList = {
    "sample": "data from data.txt file"
};

Внедрение тега ссылки

Как насчет тега ссылки CSS? Можно ли его использовать для получения данных, а также тега скрипта? Ответ положительный. Можно отложенно загрузить внешний файл таблицы стилей CSS, который будет вставлять данные внутрь тега веб-страницы через свойство content.

p.s3fc-hidden::after {
    content: "{cssJson: 'cssJsonValues'}";
}

и вот как он загружается:

    let linkTag = document.createElement("link");
    linkTag.setAttribute("rel", " stylesheet");
    linkTag.setAttribute("href", " /style.css");

    let getContent = () => document.styleSheets[document.styleSheets.length - 1]
                            .cssRules[0]
                            .styleMap.get("content");

    linkTag.onload = () => 
                console.log("Link tag injection: " + getContent());

    document.body.appendChild(linkTag);

Внедрение тега объекта

Одна из интересных идей — использовать изображение для получения данных из его содержимого. Вопрос только в формате, так как большинство изображений представлены в каком-то двоичном представлении. Исключением являются файлы изображений SVG, которые представляют собой правильно сформированные XML-файлы, представленные в текстовом формате.

<svg version="1.1"
     baseProfile="full"
     width="300" height="200"
     xmlns="http://www.w3.org/2000/svg">
  <text x="0" y="15" fill="white">{vectorSample: "data"}</text>
</svg>

Как и в предыдущих случаях, чтобы загрузить файл, нам нужно создать соответствующий тег (‹object› в данном случае ) и использовать его событие onload:

    let objectTag = document.createElement("object");
    objectTag.setAttribute("data", "/vector.svg");
    objectTag.setAttribute("width", "0");
    objectTag.setAttribute("height", "0");

    let getContent = () => 
                objectTag.contentDocument.firstChild.textContent;

    objectTag.onload = () =>  
        console.log("Object tag injection " + getContent());
    
    document.body.appendChild(objectTag);

Заворачивать

Представленные четыре способа получения данных не будут отображаться на вкладке «Сеть» инспектора браузера как AJAX-вызовы сервера. Это было целью в полном тестовом задании. Полный рабочий код тестового задания доступен для скачивания из репозитория GIT: