webRequest.StreamFilter.ondata
Обработчик событий, вызываемый многократно при поступлении данных ответа. Обработчику передается объект event, содержащий свойство data, которое включает фрагмент данных ответа в виде ArrayBuffer.
Для декодирования данных используйте либо TextDecoder, либо Blob.
Без слушателя ondata, вы не получаете исходное тело ответа, и выходной поток пуст, если не вызывается write.
Примеры
В этом примере добавляется слушатель ondata, который заменяет "Example" в ответе на "WebExtension Example" с помощью метода replaceAll().
Примечание: Этот пример работает только для вхождений "Example", полностью содержащихся в фрагменте данных, а не для тех, которые охватывают два фрагмента (что может произойти примерно в 0,1% случаев для больших документов). Кроме того, он работает только с документами, закодированными в UTF-8. Реальное решение должно быть более сложным.
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); filter.ondata = (event) => { let str = decoder.decode(event.data, { stream: true }); // Just change any instance of Example in the HTTP response // to WebExtension Example. // Note that this will maybe not work as expected because the ending of the str can also // be "<h1>Examp" (because it is not the full response). So, it is better // to get the full response first and then doing the replace. str = str.replaceAll("Example", "WebExtension Example"); filter.write(encoder.encode(str)); // Doing filter.disconnect(); here would make us process only // the first chunk, and let the rest through unchanged. Note // that this would break multi-byte characters that occur on // the chunk boundary! }; filter.onstop = (event) => { filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/*"], types: ["main_frame"] }, ["blocking"] );
Еще один пример для обработки больших документов:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(event.data); }; filter.onstop = (event) => { let str = ""; if (data.length === 1) { str = decoder.decode(data[0]); } else { for (let i = 0; i < data.length; i++) { let stream = i !== data.length - 1; str += decoder.decode(data[i], { stream }); } } str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Вот еще одна версия:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(event.data); }; filter.onstop = (event) => { let str = ""; for (const buffer of data) { str += decoder.decode(buffer, { stream: true }); } str += decoder.decode(); // end-of-stream str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Приведенный выше пример также можно записать так:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(decoder.decode(event.data, { stream: true })); }; filter.onstop = (event) => { data.push(decoder.decode()); let str = data.join(""); str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Этот пример использует Blob:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(event.data); }; filter.onstop = async (event) => { const blob = new Blob(data, { type: "text/html" }); let str = await blob.text(); str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
В этом примере используется интерфейс DOMParser:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const encoder = new TextEncoder(); const parser = new DOMParser(); const data = []; filter.ondata = (event) => { data.push(event.data); }; filter.onstop = async (event) => { const blob = new Blob(data, { type: "text/html" }); const str = await blob.text(); const doc = parser.parseFromString(str, blob.type); const nodes = doc.querySelectorAll("title, h1"); for (const node of nodes) { node.innerText = node.innerText.replaceAll("Example", "WebExtension $&"); } filter.write(encoder.encode(doc.documentElement.outerHTML)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Этот пример объединяет все буферы в один буфер:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(new Uint8Array(event.data)); }; filter.onstop = (event) => { let combinedLength = 0; for (const buffer of data) { combinedLength += buffer.length; } const combinedArray = new Uint8Array(combinedLength); let writeOffset = 0; for (const buffer of data) { combinedArray.set(buffer, writeOffset); writeOffset += buffer.length; } let str = decoder.decode(combinedArray); str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Приведенный выше пример также можно записать так:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const decoder = new TextDecoder("utf-8"); const encoder = new TextEncoder(); const data = []; filter.ondata = (event) => { data.push(event.data); }; filter.onstop = async (event) => { const blob = new Blob(data, { type: "text/html" }); const buffer = await blob.arrayBuffer(); let str = decoder.decode(buffer); str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Этот пример демонстрирует, как можно определить, является ли текущий фрагмент последним в ответе:
function listener(details) { const filter = browser.webRequest.filterResponseData(details.requestId); const encoder = new TextEncoder(); const decoder = new TextDecoder("utf-8"); let str = ""; filter.ondata = (event) => { let stream = true; const data = new Uint8Array(event.data.slice(-8, -1)); if (String.fromCharCode(...data) === "</html>") { stream = false; // end-of-stream } str += decoder.decode(event.data, { stream }); }; filter.onstop = (event) => { str = str.replaceAll("Example", "WebExtension $&"); filter.write(encoder.encode(str)); filter.close(); }; } browser.webRequest.onBeforeRequest.addListener( listener, { urls: ["https://example.com/"], types: ["main_frame"] }, ["blocking"] );
Совместимость с браузерами
| Рабочие столы | Мобильные устройства | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari на IOS | Samsung Internet | |
ondata |
Нет | Нет | 57 | ? | Нет | Нет | ? | ? | 57 | ? | Нет | ? |
© 2005–2023 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/StreamFilter/ondata