Перехватить скрипт document.createElement для изменения src

Я пытаюсь подключить document.createElement, чтобы изменить значение свойства src для каждого назначения.

Вот что я делаю:

var original = document.createElement;
    document.createElement = function (tag) {
      var element = original.call(document, tag);
      if (tag.toLowerCase() === 'script') {
        Object.defineProperty(element.__proto__, 'src', {
          set: function(newValue) {
            element['src'] = 'test';
          }
        });
      }
      return element;
    };

Проблема в том, что element['src'] = 'test'; снова и снова вызывает setter, вызывая переполнение стека. Я пробовал другой подход, когда я сохраняю локальную переменную снаружи и устанавливаю ее значение на newValue и добавляю getter к свойству src, которое вместо этого возвращает его. Проблема с этим подходом заключается в том, что если элемент сценария позже добавляется к dom, то добавляется тег сценария без атрибута src, например, метод добавления каким-то образом пытается получить свойство src другим способом, а затем обращается к нему обычно, поэтому getter не вызывается, и поэтому у меня остается пустой тег скрипта.

Что я могу сделать в этой ситуации, какие-либо мысли о том, как я могу это сделать, чтобы я мог «заменить» значение, предназначенное для использования с атрибутом src скриптов, другим значением?

Обновлено: Это крючок, который у меня получился:

    Object.defineProperty(HTMLScriptElement.prototype, 'src', {
  set: function(newValue) {
    const r = /(?:[^:]+:)?\/\//;
    if (r.test(newValue)) {
      this.setAttribute("src", 'http://localhost:8080/v1/proxy?url=' + (newValue.startsWith('http') ? encodeURIComponent(newValue) : encodeURIComponent('http:' + newValue)));
    } else {
      this.setAttribute("src", 'http://localhost:8080/v1/proxy?url=' + encodeURIComponent(absolute('${originalHost}', newValue)));
    }
  }
});

Я понял, что мне нужно охватить все возможные способы изменения атрибутов src элемента script, включая setAttribute('src', '...'). Если бы я подключил setAttribute, я бы вызвал переполнение стека, поскольку я уже подключил свойство srcsetter и использовал setAttribute внутри него. Как я могу добиться подключения setAttribute, чтобы иметь полный контроль над значением src, не вызывая переполнения стека?

Обмануть методы DOM - вообще плохая идея (tm). Вы мог пытаетесь использовать element.setAttribute("src", "test"), но это вполне может запустить тот же цикл.

Heretic Monkey 08.06.2018 23:31
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
663
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Просто замените «element['src'] = 'test';» на «element.setAttribute('src', 'test');». Таким образом, вы можете избежать использования собственности. Метод setAttribute взаимодействует с атрибутами элемента напрямую, а не через средства получения атрибутов браузера.

Опять же, это действительно плохая практика!

Grant Gryczan 08.06.2018 23:57

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

Jorayen 08.06.2018 23:59

Я думаю, что было бы намного практичнее иметь установщик для HTMLScriptElement.prototype.src, чем переназначать функцию document.createElement и делать то, что вы делаете сейчас. Это все еще плохая практика, так как вы все еще возитесь с прототипами, но это будет немного менее небрежно.

Grant Gryczan 09.06.2018 00:04

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

Jorayen 09.06.2018 00:08

Я обновил вопрос, мне нужно решение для подключения setAttribute, если у вас есть что-то на уме, я был бы признателен за любую помощь.

Jorayen 03.09.2018 21:47

Вы не должны этого делать. Вы должны сохранить Element.prototype.setAttribute в другом свойстве на Element.prototype, а затем перезаписать его. Внутри своей версии делайте то, что хотите, а затем вызывайте оригинал. Я не собираюсь приводить код, который точно показывает, как это сделать, потому что это действительно плохая практика вне отладки, как и все остальное, что вы здесь делаете.

Grant Gryczan 07.09.2018 03:20

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