我正在使用新的fetch API在Javascript中编写一个基本应用程序。以下是代码相关部分的基本示例:
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);
}
在进行获取请求时,我偶尔会在控制台中看到如下所示的错误:
拒绝加载脚本'< url>'因为它违反了以下内容安全策略指令...
在阅读并了解HTTP / 2之后,看起来会显示此消息,因为响应正在推回预加载的脚本。使用devtools,我可以在响应中看到以下标题:
链接:其中路径到脚本取代;相对=预载荷;如=脚本
以下是我的Chrome扩展程序的manifest.json文件的相关部分:
{
"content_security_policy": "script-src 'self'; object-src 'self'"
}
以下是有关Chrome的manifest.json格式的文档,以及内容安全策略如何应用于扩展程序提取的内容:https://developer.chrome.com/extensions/contentSecurityPolicy
我做了一些测试,并且能够确定在获取期间发生此错误消息,而不是在解析响应文本时。没有问题将脚本元素加载到实时DOM中,这一切都发生在获取时。
我在研究中无法找到的是如何避免这种行为。看起来急于支持这个伟大的新功能,制作HTTP / 2和fetch的人没有考虑我没有获取远程页面以便显示它或其任何相关资源(如css)的用例/图像/脚本。我(应用程序)以后不会使用任何相关资源;只有资源本身的内容。
在我的用例中,这个推送(1)完全浪费了资源,(2)现在导致一个非常恼人和压力诱导的消息偶尔出现在控制台中。
话虽如此,这是我希望得到一些帮助的问题:有没有办法向浏览器发信号,使用清单或脚本,我对HTTP / 2推送没兴趣?是否有我可以为获取请求设置的标头告诉Web服务器不响应推送?我可以在我的应用清单中使用CSP设置以某种方式触发不要推送我的响应吗?
我已经查看了https://w3c.github.io/preload/第3.3节,它没有多大帮助。我看到我可以发送Link: </dont/want/to/push/this>; rel=preload; as=script; nopush
之类的标题。问题是我还不知道响应中会有哪些链接头,我不确定fetch是否允许在初始请求中设置链接头。我想知道我是否可以发送某些类型的请求,可以看到响应中的链接头但是避免它们,然后发送追加所有相应nopush头的后续请求?
以下是重现问题的简单测试用例:
附加说明:
答案 0 :(得分:5)
在跟随您的测试用例之后,我能够通过以下方式解决此问题(示例),但我不知道它适用于所有更常见的情况:
chrome.webRequest
拦截对扩展程序请求的回复。onHeadersRecieved
的屏蔽形式删除包含rel=preload
我不得不承认我花了很多时间试图弄清楚为什么这似乎有用,因为我不认为剥离链接标题应该适用于所有情况。我认为Server Push会在发送请求后才开始推送文件。
正如您在附加说明中提到的SETTINGS_ENABLE_PUSH
其中大部分内容实际上已经融入了Chrome并且隐藏在我们的视野中。如果你想深入挖掘,我会在chrome://net-internals/#http2
找到详细信息。也许Chrome会杀死Server 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"
]
}
附加说明:
我只是天真地将此限制为扩展程序中的最新请求网址,webRequest.requestFilters
已加入chrome.webRequest
您可以查看here
您可能还希望更加具体地了解您删除哪些标题。我觉得剥离所有的链接都会有一些额外的效果。
这可以避免使用代理,也不需要在请求中设置链接标头。
这是一个非常强大的扩展,我个人避免使用<all_urls>
这样的权限扩展,希望您可以缩小范围。
我没有测试因阻止删除标题的响应而导致的延迟。