Чи можна створити розширення Chrome, яке змінює тіла відповіді HTTP?
Я заглянув у API розширень Chrome , але не знайшов для цього.
Чи можна створити розширення Chrome, яке змінює тіла відповіді HTTP?
Я заглянув у API розширень Chrome , але не знайшов для цього.
webRequest.filterResponseData()
. На жаль, це рішення лише для Firefox.
Відповіді:
Загалом, ви не можете змінити тіло відповіді на запит HTTP, використовуючи стандартні API розширення Chrome.
Цю функцію запитують за адресою 104058: WebRequest API: дозволити розширення редагувати тіло відповіді . Позначте цю зірочку, щоб отримувати сповіщення про оновлення.
Якщо ви хочете відредагувати тіло відповіді для відомого XMLHttpRequest
, введіть код за допомогою сценарію вмісту, щоб замінити XMLHttpRequest
конструктор за замовчуванням на власний (повнофункціональний), який переписує відповідь перед активацією реальної події. Переконайтеся, що ваш об’єкт XMLHttpRequest повністю відповідає вбудованому XMLHttpRequest
об’єкту Chrome, інакше сайти, важкі для AJAX, зламаються.
В інших випадках ви можете використовувати API chrome.webRequest
або chrome.declarativeWebRequest
API для перенаправлення запиту на data:
-URI. На відміну від підходу XHR, ви не отримаєте оригінальний вміст запиту. Насправді, запит ніколи не потрапить на сервер, оскільки перенаправлення може бути здійснено лише до того, як буде відправлений фактичний запит. І якщо ви перенаправите main_frame
запит, користувач побачить data:
-URI замість запитуваної URL-адреси.
data:text...
?
Я щойно випустив розширення Devtools, яке робить саме це :)
Це називається тампер, воно базується на 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 .
Це рішення запропоновано коментарем до випуску Chrome 487422 :
Для тих, хто хоче альтернативу, яка є здійсненною на даний момент, ви можете використати
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
метод представляється не включені в v1.2 протоколу DevTools, і я не можу знайти спосіб , щоб прикріпити її з останньої (наконечник-з-дерева) версії замість.
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
замість нього