Как отказаться от HTTP / 2 server push при использовании fetch?
Я пишу базовое приложение на Javascript, которое использует новый API выборки. Вот основной пример соответствующей части кода:
function foo(url) {
const options = {};
options.credentials = 'omit';
options.method = 'get';
options.headers = {'Accept': 'text/html'};
options.mode = 'cors';
options.cache = 'default';
options.redirect = 'follow';
options.referrer = 'no-referrer';
options.referrerPolicy = 'no-referrer';
return fetch(url, options);
}
при выполнении запроса выборки я иногда вижу, что в консоли появляются ошибки, которые выглядят следующим образом:
отказался загружать скрипт ' ', поскольку он нарушает следующую директиву политики безопасности контента ...
после некоторого чтения и изучения HTTP / 2, это выглядит так это сообщение появляется, потому что ответ отталкивает предварительно загруженный сценарий. Используя devtools, я вижу следующий заголовок в ответе:
ссылка:; rel=предварительная загрузка; as=script
вот соответствующая часть манифеста моего расширения Chrome.файл json:
{
"content_security_policy": "script-src 'self'; object-src 'self'"
}
вот документация по манифесту Chrome.формат json и применение политики безопасности содержимого к выборкам, выполняемым расширением: https://developer.chrome.com/extensions/contentSecurityPolicy
Я провел некоторое тестирование и смог определить, что это сообщение об ошибке происходит во время выборки, а не позже при разборе текста ответа. Нет проблем, когда элемент сценария загружается в live DOM, все это происходит во время выборки.
в моем случае использования этот толчок (1) является полной тратой ресурсов, и (2) теперь вызывает действительно раздражающее и вызывающее стресс сообщение, которое спорадически появляется в приставка.
С учетом сказанного, вот вопрос, с которым я хотел бы помочь: есть ли способ сигнализировать браузеру, используя манифест или скрипт, что я не заинтересован в HTTP/2 push? Есть ли заголовок, который я могу установить для запроса выборки, который говорит веб-серверу не отвечать push? Есть ли параметр CSP, который я могу использовать в манифесте приложения, который каким-то образом запускает ответ "не толкайте меня"?
Я посмотрел на https://w3c.github.io/preload/ раздел 3.3, it это не очень помогло. Я вижу, что могу отправлять заголовки типа Link: </dont/want/to/push/this>; rel=preload; as=script; nopush
. Проблема в том, что я еще не знаю, какие заголовки ссылок будут в ответе, и я не уверен, что fetch даже разрешает устанавливать заголовки ссылок в начальном запросе. Интересно, могу ли я отправить какой-то запрос, который может видеть заголовки ссылок в ответе, но избегает их, а затем отправить следующий запрос, который добавляет все соответствующие заголовки nopush?
вот простой тестовый пример для воспроизведения выпуск:
- получить dev версию последней или около последней chrome
- создать папку расширения
- создать манифест с аналогичным CSP
- загрузить расширение как распаковано в chrome
- откройте фоновую страницу для расширения в devtools
- в консоли введите fetch ('https://www.yahoo.com').
- Проверьте полученное сообщение об ошибке, которое появляется в консоли:отказалась чтобы загрузить скрипт'https://www.yahoo.com/sy/rq/darla/2-9-20/js/g-r-min.js ' потому что это нарушает следующую директиву политики безопасности контента:"script-src 'self'".
дополнительно:
- я не хочу использовать прокси-сервер. Ясное объяснение, почему это было бы моим единственным вариантом, было бы приемлемым ответом.
- я не знаю URL, которые будут извлечены во время настройки СПС.
- см.https://tools.ietf.org/html/rfc7540#section-6.5.1 в соответствующей части указано ,что " SETTINGS_ENABLE_PUSH (0x2): этот параметр можно использовать для отключения push-сервера (раздел 8.2). Конечная точка не должна отправлять кадр PUSH_PROMISE, если она получает этот параметр, установленный в значение 0."Есть ли способ указать этот параметр из сценария или манифеста или он запечен в Chrome?
1 ответов
после следования вместе с вашим тестовым случаем я смог решить эту (пример) проблему следующим образом, хотя я не знаю, что это относится ко всем более общим случаям:
- использовать
chrome.webRequest
для перехвата ответов на запросы расширения. - используйте блокирующую форму
onHeadersRecieved
чтобы удалить заголовки, содержащиеrel=preload
- разрешить ответу перейти к обновленным заголовкам.
должен признаться, я потратил много времени, пытаясь понять, почему это сработало, поскольку я не думаю, что удаление заголовков ссылок должно работать во всех случаях. Я думал, что сервер Push просто начнет толкать файлы после отправки запроса.
как вы упомянули в своем дополнительном примечании о SETTINGS_ENABLE_PUSH
многое из этого на самом деле запечено в хроме и скрыто от нашего взгляда. Если вы хотите копать глубже, я нашел детали в chrome://net-internals/#http2
. Возможно, Chrome убивает файлы, отправленные сервером Push, у которых нет соответствующий заголовок ссылки в исходном ответе.
это решение зависит от chrome.webRequest
Docs
фоновый скрипт расширения:
let trackedUrl;
function foo(url) {
trackedUrl = url;
const options = {};
options.credentials = 'omit';
options.method = 'get';
options.headers = { 'Accept': 'text/html' };
options.mode = 'cors';
options.cache = 'default';
options.redirect = 'follow';
options.referrer = 'no-referrer';
options.referrerPolicy = 'no-referrer';
return fetch(url, options)
}
chrome.webRequest.onHeadersReceived.addListener(function (details) {
let newHeaders;
if (details.url.indexOf(trackedUrl) > -1) {
newHeaders = details.responseHeaders.filter(header => {
return header.value.indexOf('rel=preload') < 0;
})
}
return { responseHeaders: newHeaders };
}, { urls: ['<all_urls>'] }, ['responseHeaders', 'blocking']);
манифест расширения:
{
"manifest_version": 2,
"name": "Example",
"description": "WebRequest Blocking",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": [
"back.js"
]
},
"content_security_policy": "script-src 'self'; object-src 'self'",
"permissions": [
"<all_urls>",
"background",
"webRequest",
"webRequestBlocking"
]
}
Дополнительная Информация:
Я просто наивно ограничиваю это последним url-адресом запроса от расширения, есть
webRequest.requestFilters
запеченные вchrome.webRequest
вы можете проверить здесьвы, вероятно,также захотите быть более конкретными о том, какие заголовки вы снимаете. Я чувствую, что удаление всех ссылок будет иметь некоторые дополнительные эффекты.
это позволяет избежать прокси и не требует установки заголовка ссылки в запросе.
это делает довольно мощное расширение, лично я избегаю расширений с разрешениями, такими как
<all_urls>
, надеюсь, вы можете сузить масштаб.Я не проверял задержки, вызванные блокировкой ответов на удаление заголовков.