我正在开发一个Chrome扩展程序,可以将某些网站的请求发送到我控制的API。在Chrome 73之前,扩展程序正常运行。升级到Chrome 73后,我开始收到以下错误:
跨源读取阻塞(CORB)阻止了具有MIME类型application / json的跨源响应http://localhost:3000/api/users/1
根据Chrome's documentation on CORB的说法,如果满足以下所有条件,CORB将阻止请求的响应:
X-Content-Type-Options: nosniff
标头进行响应,或者如果省略此标头,Chrome会检测内容类型是检查文件中的HTML,XML或JSON之一此外,根据"Lessons from Spectre and Meltdown" (Google I/O 2018),似乎将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阻止?
基于"Changes to Cross-Origin Requests in Chrome Extension Content Scripts"中的示例,我用一个新方法fetch
替换了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 Response对象从后台页面传递给扩展。)
后台页面不受CORS或CORB的影响,因此浏览器不再阻止来自API的响应。
临时解决方案:使用运行命令浏览器--disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating
禁用CORB
Linux上的示例运行命令。
对于Chrome:
chrome %U --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating
对于铬:
chromium-browser %U --disable-features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating
见https://www.chromium.org/Home/chromium-security/extension-content-script-fetches
为了提高安全性,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 => ...);
新的扩展背景页面,从已知URL获取并中继数据:
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.
}
});