Как управлять объектом XMLHttpRequest на HTML5 Web Worker? - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть страница, которая обычно переопределяет window.XMLHttpRequest с оберткой, которая выполняет несколько дополнительных операций, таких как вставка в заголовки для определенных запросов.

У меня есть некоторые функции в сторонней библиотеке, которая использует HTML5 Workerи мы видим, что этот запрос не использует объект-оболочку XMLHttpRequest.Таким образом, в любом запросе этой библиотеки отсутствуют требуемые заголовки, поэтому запрос не будет выполнен.

Есть ли способ управления запросом XMLHttpRequest, который создает любой рабочий в текущем потоке?

Это 3-йКод сторонней библиотеки выглядит следующим образом:

        function createWorker(url) {
            var worker = new Worker(url);
            worker.onmessage = function (e) {
                if (e.data.status) {
                    onprogress(e.data.status);
                } else if (e.data.error) {
                    onerror(e.data.error);
                } else {
                    exportUtils.saveFile(new Blob([e.data]), params.fileName);
                    onfinish();
                }
            };
            worker.postMessage(params); // window.location.origin +
            return worker;
        }

Javascript, возвращаемый переменной URL выше, содержит код, подобный следующему:

        return new Promise(function(t, r) {
            var n = new XMLHttpRequest
              , a = "batch_" + o()
              , u = e.dataUrl.split(e.serviceUrl)[1]
              , c = [];
            n.onload = function() {
                for (var e = this.responseText, n = this.responseText.split("\r\n"), o = 0, a = n.length, i = a - 1; o < a && "{" !== n[o].slice(0, 1); )
                    o++;
                for (; i > 0 && "}" !== n[i].slice(-1); )
                    i--;
                n = n.slice(o, i + 1),
                e = n.join("\r\n");
                try {
                    var u = JSON.parse(e);
                    t(u)
                } catch (t) {
                    r(s + e)
                }
            }
            ,
            n.onerror = function() {
                r(i)
            }
            ,
            n.onabort = function() {
                r(i)
            }
            ,
            n.open("POST", e.serviceUrl + "$batch", !0),
            n.setRequestHeader("Accept", "multipart/mixed"),
            n.setRequestHeader("Content-Type", "multipart/mixed;boundary=" + a);
            for (var p in e.headers)
                "accept" != p.toLowerCase() && n.setRequestHeader(p, e.headers[p]);
            c.push("--" + a),
            c.push("Content-Type: application/http"),
            c.push("Content-Transfer-Encoding: binary"),
            c.push(""),
            c.push("GET " + u + " HTTP/1.1");
            for (var p in e.headers)
                c.push(p + ":" + e.headers[p]);
            c.push(""),
            c.push(""),
            c.push("--" + a + "--"),
            c.push(""),
            c = c.join("\r\n"),
            n.send(c)
        }
        )

1 Ответ

0 голосов
/ 21 ноября 2018

Ответом является как мягкое «нет», так и возможное «да».

Когда фрагмент кода работает в другом контексте (например, веб-работник или iframe), у вас нет прямого контроляглобального объекта (1).

Более того, XMLHttpRequest - не единственный способ отправки сетевых запросов - у вас есть несколько других методов, главным из которых является fetch api .

Тем не менее, в блоке есть относительно новый ребенок под названием «Рабочие службы», который может вам немало помочь!

Служащие службы

Служащие службы (Аббревиатуры SW) очень похожи на тех веб-работников, которых вы уже знаете, но вместо того, чтобы работать только на текущей странице, они продолжают работать в фоновом режиме, пока ваш пользователь остается в вашем домене.Они также глобальны для всего вашего домена , поэтому любые запросы, сделанные с вашего сайта, будут проходить через них.

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

Давайте рассмотрим небольшой пример (обратите внимание, запустите их с локального веб-сервера):

// index.html
<script>
navigator.serviceWorker.register('sw.js')
    .then(console.log.bind(console, 'SW registered!'))
    .catch(console.error.bind(console, 'Oh nose!'));

setInterval(() => {
    fetch('/hello/');
}, 5000);
</script>

// sw.js
console.log('Hello from a friendly service worker');

addEventListener('fetch', event => {
    console.log('fetch!', event);
})

Здесь мы регистрируемсяработник службы, а затем запрашивает страницу каждые 5 секунд.В сервисном работнике мы просто регистрируем каждое сетевое событие, которое может быть зафиксировано в событии fetch.

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

Круто!Из возни с событием в консоли видно, что event.request - это объект Request, созданный нашим браузером.В идеальном мире мы могли бы получить доступ к event.request.headers и добавить наши собственные заголовки!Мечтательно, не правда ли??

К сожалению, заголовки запроса / ответа защищены и неизменны .К счастью, мы упрямая группа и можем просто пересоздать запрос:

// sw.js
console.log('Hello from a friendly service worker');

addEventListener('fetch', event => {
    console.log('fetch!', event);
    // extract our request
    const { request } = event;

    // clone the current headers
    const newHeaders = new Headers();
    for (const [key, val] of request.headers) {
        newHeaders.append(key, val);
    }
    // ...and add one of our own
    newHeaders.append('Say-What', 'You heard me!');

    // clone the request, but override the headers with our own
    const superDuperReq = new Request(request, {
        headers: newHeaders
    });

    // now instead of the original request, our new request will take precedence!
    return fetch(superDuperReq);
});

Это несколько разных концепций в игре, так что все в порядке, если требуется несколько раз, чтобы получить.По сути, мы создаем новый запрос, который будет отправлен вместо исходного, и устанавливаем новый заголовок!Ура!

enter image description here

Плохое

Теперь о некоторых недостатках:

  • Так как мыПерехищая каждый запрос , мы можем случайно изменить запросы, которые мы не собирались, и потенциально уничтожить всю вселенную!
  • Обновление ПО - огромная боль.Жизненный цикл ПО сложен, отладка его для ваших пользователей затруднительна.Я видел хорошее видео о том, как справиться с этим, но, к сожалению, не могу найти его прямо сейчас, но mdn имеет довольно хорошее описание
  • Отладка SW часто очень раздражает, особеннов сочетании с их странными жизненными циклами
  • Поскольку они настолько мощные, СР могут обслуживаться только через https.Вы уже должны использовать https в любом случае, но это все еще является помехой
  • Это много вещей, которые нужно сделать для сравнительно небольшого преимущества, поэтому, возможно, пересмотреть его необходимость

(1) Вы можете получить доступ к глобальному объекту iframe в того же источника , что и у вас, но получить код для запуска first для изменения глобального объекта действительно сложно.

...