如何在严格CSP的网站上为Chrome扩展内容脚本运行WebWorker?
可行解决方案
针对Chrome扩展在CSP严格站点无法运行Tesseract.js Worker的问题,以下是几种无需每次新开标签的方案:
1. 使用扩展沙箱页面(Sandboxed Page)
沙箱页面是Chrome扩展提供的独立执行环境,不受宿主页面CSP限制,适合处理需要绕过CSP的脚本任务。
配置步骤
- 在
manifest.json中添加沙箱配置,指定允许脚本执行和本地资源访问:
{ "manifest_version": 3, // 其他扩展配置... "sandbox": { "pages": ["sandbox.html"], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" } }
- 将
tesseract.min.js、worker.min.js及Tesseract语言包(如eng.traineddata)放在扩展目录下。
沙箱页面逻辑(sandbox.html)
创建专门处理OCR的沙箱页面,通过扩展消息系统接收截图数据并返回识别结果:
<!DOCTYPE html> <html> <body> <script src="tesseract.min.js"></script> <script> chrome.runtime.onMessage.addListener(async (msg, sender, sendResponse) => { if (msg.action === 'ocr') { // 初始化Worker,指定扩展内的资源路径 const worker = await Tesseract.createWorker({ workerPath: chrome.runtime.getURL('worker.min.js'), langPath: chrome.runtime.getURL('langs/'), lang: 'eng' }); // 执行OCR识别 const result = await worker.recognize(msg.imageData); await worker.terminate(); // 返回识别文本 sendResponse({ text: result.data.text }); } return true; // 标记异步响应 }); </script> </body> </html>
内容脚本调用
内容脚本只需将截图数据(如base64格式的图片)发送给沙箱页面,等待结果返回:
// 假设已获取网页截图的base64数据 const screenshotBase64 = 'data:image/png;base64,...'; chrome.runtime.sendMessage({ action: 'ocr', imageData: screenshotBase64 }, (response) => { console.log('OCR识别结果:', response.text); });
2. 使用Offscreen Document(Chrome 109+)
Offscreen Document是Chrome 109版本引入的轻量级后台文档,专为扩展处理后台任务设计,无需显示UI,且完全隔离于宿主页面CSP。
配置步骤
- 在
manifest.json中注册Offscreen文档:
{ "manifest_version": 3, // 其他扩展配置... "offscreen": { "matches": ["<all_urls>"], "documents": ["offscreen.html"] } }
Offscreen页面逻辑(offscreen.html)
逻辑与沙箱页面类似,通过消息系统处理OCR任务:
<!DOCTYPE html> <html> <body> <script src="tesseract.min.js"></script> <script> chrome.runtime.onMessage.addListener(async (msg, sender, sendResponse) => { if (msg.action === 'runOcr') { const worker = await Tesseract.createWorker({ workerPath: chrome.runtime.getURL('worker.min.js'), langPath: chrome.runtime.getURL('langs/'), lang: 'eng' }); const result = await worker.recognize(msg.image); await worker.terminate(); sendResponse({ text: result.data.text }); } return true; }); </script> </body> </html>
内容脚本调用
先确保Offscreen文档已创建,再发送任务:
// 初始化Offscreen文档 async function initOffscreen() { if (!(await chrome.offscreen.hasDocument())) { await chrome.offscreen.createDocument({ url: 'offscreen.html', reasons: ['DOM_SCRAPING'], justification: '执行网页截图OCR识别' }); } } // 调用OCR async function runOcr(screenshot) { await initOffscreen(); return chrome.runtime.sendMessage({ action: 'runOcr', image: screenshot }); } // 使用示例 runOcr('data:image/png;base64,...').then(res => { console.log('识别结果:', res.text); });
3. 预加载隐藏的扩展标签页
创建一个隐藏的扩展标签页作为持久OCR后台,只需初始化一次,后续重复使用:
初始化隐藏标签页(在Service Worker中)
let ocrTabId = null; async function createHiddenOcrTab() { if (!ocrTabId) { const tab = await chrome.tabs.create({ url: chrome.runtime.getURL('ocr-background.html'), active: false, hidden: true }); ocrTabId = tab.id; } } // 扩展启动时创建 chrome.runtime.onStartup.addListener(createHiddenOcrTab); chrome.runtime.onInstalled.addListener(createHiddenOcrTab);
OCR后台页面(ocr-background.html)
逻辑与前两种方案一致,通过消息接收截图数据并执行OCR,此处不再重复代码。
内容脚本调用
直接向隐藏标签页发送消息:
chrome.tabs.sendMessage(ocrTabId, { action: 'ocr', imageData: screenshotBase64 }, (response) => { console.log('识别结果:', response.text); });
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

