Я пытаюсь подключить 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, не вызывая переполнения стека?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это действительно плохая практика - возиться с методами и прототипами, которые вы не создавали, но в любом случае здесь может быть ваше решение.
Просто замените «element['src'] = 'test';» на «element.setAttribute('src', 'test');». Таким образом, вы можете избежать использования собственности. Метод setAttribute взаимодействует с атрибутами элемента напрямую, а не через средства получения атрибутов браузера.
Опять же, это действительно плохая практика!
Спасибо, сработало. Я знаю, что это плохая практика, но я пытаюсь достичь того, чего, по моему мнению, нельзя добиться иначе. Я хочу перехватить все загруженные асинхронно скрипты, чтобы перенаправить их на мой прокси. Я пробовал статический подход к анализу всех назначений файла сценария (даже запутанных), но у него просто слишком много крайних случаев, которые нельзя решить без оценки части кода, что исключает эту цель статического анализа (скажем, кто-то используйте простое шифрование, например xor, для преобразования переменной в src, а затем используйте его для присвоения значения). Если у вас есть представление получше, я весь уши. :)
Я думаю, что было бы намного практичнее иметь установщик для HTMLScriptElement.prototype.src, чем переназначать функцию document.createElement и делать то, что вы делаете сейчас. Это все еще плохая практика, так как вы все еще возитесь с прототипами, но это будет немного менее небрежно.
Спасибо за предложение, которое я сделал бы, и снова должен работать с тем, что у меня нет лучшего решения, я думаю :)
Я обновил вопрос, мне нужно решение для подключения setAttribute, если у вас есть что-то на уме, я был бы признателен за любую помощь.
Вы не должны этого делать. Вы должны сохранить Element.prototype.setAttribute в другом свойстве на Element.prototype, а затем перезаписать его. Внутри своей версии делайте то, что хотите, а затем вызывайте оригинал. Я не собираюсь приводить код, который точно показывает, как это сделать, потому что это действительно плохая практика вне отладки, как и все остальное, что вы здесь делаете.
Обмануть методы DOM - вообще плохая идея (tm). Вы мог пытаетесь использовать
element.setAttribute("src", "test"), но это вполне может запустить тот же цикл.