Google chrome 如何阻止CORB阻止对响应CORS头的数据资源的请求?
我正在开发一个Chrome扩展,它可以从某些网站向我控制的API发出请求。在Chrome 73之前,分机工作正常。升级到Chrome 73后,我开始出现以下错误: 跨源读取阻塞(CORB)阻塞的跨源响应 使用MIME类型的application/json 根据,如果满足以下所有条件,CORB将阻止请求响应:Google chrome 如何阻止CORB阻止对响应CORS头的数据资源的请求?,google-chrome,google-chrome-extension,cors,cross-origin-read-blocking,Google Chrome,Google Chrome Extension,Cors,Cross Origin Read Blocking,我正在开发一个Chrome扩展,它可以从某些网站向我控制的API发出请求。在Chrome 73之前,分机工作正常。升级到Chrome 73后,我开始出现以下错误: 跨源读取阻塞(CORB)阻塞的跨源响应 使用MIME类型的application/json 根据,如果满足以下所有条件,CORB将阻止请求响应: 该资源是“数据资源”。具体来说,内容类型是HTML、XML、JSON 服务器以X-Content-Type-Options:nosniff头响应,或者如果省略了此头,Chrome会通过检查文
X-Content-Type-Options:nosniff
头响应,或者如果省略了此头,Chrome会通过检查文件检测到内容类型是HTML、XML或JSON之一mode:cors
添加到fetch
调用中可能很重要,即fetch(url,{mode:'cors})
为了解决此问题,我做了以下更改:
首先,我在API的所有响应中添加了以下标题:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Origin: https://www.example.com
其次,我更新了扩展上的fetch()
调用,如下所示:
fetch(url, { credentials: 'include', mode: 'cors' })
然而,这些改变并没有奏效。我可以更改什么以使我的请求不被CORB阻止?根据中的示例,我用一个新方法fetchResource
替换了fetchResource
的所有调用,该方法具有类似的API,但将fetch
调用委托给后台页面:
// contentScript.js
function fetchResource(input, init) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage({input, init}, messageResponse => {
const [response, error] = messageResponse;
if (response === null) {
reject(error);
} else {
// Use undefined on a 204 - No Content
const body = response.body ? new Blob([response.body]) : undefined;
resolve(new Response(body, {
status: response.status,
statusText: response.statusText,
}));
}
});
});
}
// background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
fetch(request.input, request.init).then(function(response) {
return response.text().then(function(text) {
sendResponse([{
body: text,
status: response.status,
statusText: response.statusText,
}, null]);
});
}, function(error) {
sendResponse([null, error]);
});
return true;
});
这是我能够对我的应用程序进行的修复问题的最小更改集。(注意,扩展和后台页面只能在它们之间传递JSON可序列化对象,因此我们不能简单地将Fetch API响应对象从后台页面传递到扩展。)
后台页面不受CORS或CORB的影响,因此浏览器不再阻止来自API的响应。请参阅
为了提高安全性,自Chrome 85以来,Chrome扩展中不允许从内容脚本进行跨源提取。这样的请求可以从扩展后台脚本发出,并在需要时转发到内容脚本
您可以这样做以避免交叉原点
旧内容脚本,进行跨源提取:
var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => ...)
.catch(error => ...)
chrome.runtime.sendMessage(
{contentScriptQuery: "queryPrice", itemId: 12345},
price => ...);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryPrice") {
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => sendResponse(price))
.catch(error => ...)
return true; // Will respond asynchronously.
}
});
新内容脚本,要求其后台页面取回数据:
var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => ...)
.catch(error => ...)
chrome.runtime.sendMessage(
{contentScriptQuery: "queryPrice", itemId: 12345},
price => ...);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryPrice") {
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => sendResponse(price))
.catch(error => ...)
return true; // Will respond asynchronously.
}
});
新建扩展背景页,从已知URL获取并转发数据:
var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => ...)
.catch(error => ...)
chrome.runtime.sendMessage(
{contentScriptQuery: "queryPrice", itemId: 12345},
price => ...);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryPrice") {
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => sendResponse(price))
.catch(error => ...)
return true; // Will respond asynchronously.
}
});
允许manifest.json中的URL():
- ManifestV2(经典):
“权限”:[“https://another-site.com/“]
- ManifestV3():
“主机权限”:[“https://another-site.com/“]
--禁用功能=交叉站点文档阻止始终,交叉站点文档阻止隔离
Linux上的run命令示例
对于铬:
var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => ...)
.catch(error => ...)
chrome.runtime.sendMessage(
{contentScriptQuery: "queryPrice", itemId: 12345},
price => ...);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryPrice") {
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => sendResponse(price))
.catch(error => ...)
return true; // Will respond asynchronously.
}
});
chrome%U--禁用功能=交叉站点文档阻止始终,交叉站点文档阻止隔离
对于铬:
var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => ...)
.catch(error => ...)
chrome.runtime.sendMessage(
{contentScriptQuery: "queryPrice", itemId: 12345},
price => ...);
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.contentScriptQuery == "queryPrice") {
var url = "https://another-site.com/price-query?itemId=" +
encodeURIComponent(request.itemId);
fetch(url)
.then(response => response.text())
.then(text => parsePrice(text))
.then(price => sendResponse(price))
.catch(error => ...)
return true; // Will respond asynchronously.
}
});
chromium浏览器%U--禁用功能=交叉站点文档阻止始终,交叉站点文档阻止隔离
在谷歌的一篇针对扩展的文章中可以看到解决方案。我认为如果你能给出一个答案——也许有一些你认为相关的额外细节——可能会更好,因为你知道的更多。我只知道这篇文章,不知道它的细节。另请参阅,尽管使用背景页面足以解决问题,但我仍然不明白为什么Chrome阻止了我的扩展请求。“Chrome扩展内容脚本中跨源请求的更改”文章写道,“为了缓解这些担忧,Chrome的未来版本将限制内容脚本与页面本身可以执行的获取相同。”这向我表明,跨源请求仍然可以从扩展中进行,但它们必须遵循CORS。既然我在回复中添加了CORS标题,那么我的请求就不应该成功了吗?我也对这个问题的答案感兴趣。启用NetworkService的Chrome 73似乎只是没有对从内容脚本发出的xhr请求发出CORS飞行前请求,即使该请求需要CORS,并且如果从主机页发出,将触发飞行前请求。这可能是一个Chrome bug?根据文档,他们的意图是使内容脚本“遵守与他们运行的页面相同的请求规则”。如果从页面发出的x-origin请求触发了预飞行,但从内容脚本发出的请求没有触发预飞行,这似乎破坏了该意图。我不确定使用
response.text()
,new Blob([response.body])
是否是重建响应对象最可靠的方法,但它在我的应用程序中工作,我只处理JSON响应。我也不知道如何传递头。但是,对于进行自己API调用的第三方组件,我们可以做些什么:/Nice,copy和pastable代码。你应该接受这个答案,顺便说一句,不知道为什么,但因为Chrome81,情况似乎不是这样。后台脚本似乎被禁止进行fetch
调用。通过此更改,我收到以下错误:Unchecked runtime.lastError:消息端口在收到响应之前关闭。有没有想过如何解决这个问题?