Можно ли создать расширение Chrome, изменяющее тела ответов HTTP?
Я просмотрел API-интерфейсы расширений Chrome , но не нашел ничего для этого.
Можно ли создать расширение Chrome, изменяющее тела ответов HTTP?
Я просмотрел API-интерфейсы расширений Chrome , но не нашел ничего для этого.
webRequest.filterResponseData()
. К сожалению, это решение только для Firefox.
Ответы:
Как правило, вы не можете изменить тело ответа HTTP-запроса с помощью стандартных API-интерфейсов расширения Chrome.
Эта функция запрашивается по адресу 104058: API WebRequest: разрешить расширению редактировать тело ответа . Пометьте проблему, чтобы получать уведомления об обновлениях.
Если вы хотите отредактировать тело ответа для известного XMLHttpRequest
, введите код через сценарий содержимого, чтобы заменить XMLHttpRequest
конструктор по умолчанию пользовательским (полнофункциональным), который перезаписывает ответ перед запуском реального события. Убедитесь, что ваш объект XMLHttpRequest полностью совместим со встроенным XMLHttpRequest
объектом Chrome , иначе сайты с AJAX-загрузкой сломаются.
В других случаях вы можете использовать API-интерфейсы chrome.webRequest
или chrome.declarativeWebRequest
для перенаправления запроса на data:
-URI. В отличие от XHR-подхода, вы не получите исходное содержимое запроса. Фактически, запрос никогда не попадет на сервер, потому что перенаправление может быть выполнено только до отправки фактического запроса. А если вы перенаправите main_frame
запрос, пользователь увидит data:
-URI вместо запрошенного URL.
data:text...
?
Я только что выпустил расширение Devtools, которое делает именно это :)
Это называется tamper, он основан на mitmproxy и позволяет вам видеть все запросы, сделанные текущей вкладкой, изменять их и обслуживать измененную версию при следующем обновлении.
Это довольно ранняя версия, но она должна быть совместима с OS X и Windows. Сообщите мне, если это не сработает для вас.
Вы можете получить его здесь http://dutzi.github.io/tamper/
Как это работает
Как прокомментировал @Xan ниже, расширение обменивается данными через собственный обмен сообщениями с помощью скрипта python, который расширяет mitmproxy .
В расширении перечислены все запросы, использующие chrome.devtools.network.onRequestFinished
.
Когда вы щелкаете по запросу, он загружает свой ответ, используя метод объекта запроса getContent()
, а затем отправляет этот ответ скрипту python, который сохраняет его локально.
Затем он открывает файл в редакторе (используется call
для OSX или subprocess.Popen
для Windows).
Сценарий python использует mitmproxy для прослушивания всех сообщений, передаваемых через этот прокси, если он обнаруживает запрос на файл, который был сохранен, он вместо этого обслуживает файл, который был сохранен.
Я использовал API прокси-сервера Chrome (в частности chrome.proxy.settings.set()
), чтобы установить PAC в качестве настройки прокси. Этот файл PAC перенаправляет все сообщения на прокси-сервер сценария python.
Одна из величайших особенностей mitmproxy заключается в том, что он также может изменять связь по протоколу HTTP. Так что у вас тоже есть :)
Да. Это возможно с помощью chrome.debugger
API, который предоставляет расширению доступ к протоколу Chrome DevTools , который поддерживает перехват и изменение HTTP через свой сетевой API .
Это решение было предложено в комментарии к проблеме 487422 Chrome :
Для тех, кому нужна альтернатива, которая возможна на данный момент, вы можете использовать
chrome.debugger
на странице фона / события, чтобы прикрепить к конкретной вкладке, которую вы хотите прослушать (или прикрепить ко всем вкладкам, если это возможно, не тестировали все вкладки лично) , затем используйте сетевой API протокола отладки.Единственная проблема с этим заключается в том, что в верхней части области просмотра вкладки будет обычная желтая полоса, если пользователь не отключит ее
chrome://flags
.
Сначала прикрепите к цели отладчик:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
// TODO
});
});
Далее отправляем Network.setRequestInterceptionEnabled
команду, которая включит перехват сетевых запросов:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
});
});
Chrome начнет отправлять Network.requestIntercepted
события. Добавьте для них слушателя:
chrome.debugger.getTargets((targets) => {
let target = /* Find the target. */;
let debuggee = { targetId: target.id };
chrome.debugger.attach(debuggee, "1.2", () => {
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
});
chrome.debugger.onEvent.addListener((source, method, params) => {
if(source.targetId === target.id && method === "Network.requestIntercepted") {
// TODO
}
});
});
В слушателе params.request
будет соответствующий Request
объект.
Отправьте ответ с помощью Network.continueInterceptedRequest
:
rawResponse
.params.interceptionId
как interceptionId
.Обратите внимание, что я вообще ничего из этого не тестировал.
setRequestInterceptionEnabled
метод, похоже, не включен в протокол DevTools v1.2, и я не могу найти способ прикрепить его к последней версии (вершина дерева).
chrome.debugger.sendCommand(debuggee, "Network.setRequestInterceptionEnabled", { enabled: true });
сбой с 'Network.setRequestInterceptionEnabled' не найден '
Как сказал @Rob w, я переопределил, XMLHttpRequest
и это результат модификации любых запросов XHR на любых сайтах (работающих как прозрачный прокси-сервер модификации):
var _open = XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function (method, URL) {
var _onreadystatechange = this.onreadystatechange,
_this = this;
_this.onreadystatechange = function () {
// catch only completed 'api/search/universal' requests
if (_this.readyState === 4 && _this.status === 200 && ~URL.indexOf('api/search/universal')) {
try {
//////////////////////////////////////
// THIS IS ACTIONS FOR YOUR REQUEST //
// EXAMPLE: //
//////////////////////////////////////
var data = JSON.parse(_this.responseText); // {"fields": ["a","b"]}
if (data.fields) {
data.fields.push('c','d');
}
// rewrite responseText
Object.defineProperty(_this, 'responseText', {value: JSON.stringify(data)});
/////////////// END //////////////////
} catch (e) {}
console.log('Caught! :)', method, URL/*, _this.responseText*/);
}
// call original callback
if (_onreadystatechange) _onreadystatechange.apply(this, arguments);
};
// detect any onreadystatechange changing
Object.defineProperty(this, "onreadystatechange", {
get: function () {
return _onreadystatechange;
},
set: function (value) {
_onreadystatechange = value;
}
});
return _open.apply(_this, arguments);
};
например, этот код может успешно использоваться Tampermonkey для внесения любых изменений на любых сайтах :)
response
а не responseText
, так что все , что вам нужно сделать , это изменить Object.defineProperty использовать response
вместо