Chrome Extension v3迁移遇runtime.lastError连接错误,求技术协助
问题描述
我正在开发一款基于OpenAI API的Chrome扩展,功能是对网页选中的文本生成摘要或提取要点。目前正将其从manifest v2迁移至manifest v3,运行代码时出现错误:Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist。我是Chrome扩展开发新手,附上相关代码,恳请提供解决建议与技术帮助。
manifest.json 文件
{ "manifest_version": 3, "name": "Text Summarizer and Major Points generator", "version": "1.0", "description": "A Chrome extension that uses OpenAI API to summarize or produce major poinnts on the selected text.", "permissions": [ "contextMenus", "storage", "activeTab", "scripting", "tabs" ], "action": { "default_popup": "popup.html" }, "icons": { "16": "images/icon16.png", "48": "images/icon48.png", "128": "images/icon128.png" }, "host_permissions": [ "https://*.openai.com/" ], "background": { "service_worker": "background.js" }, "options_page": "options.html" }
background.js 文件
// background.js // Generate a menu that gives an option for summary generation and major point generation chrome.runtime.onInstalled.addListener(function () { chrome.contextMenus.create({ id: 'summarize', title: 'Summarize it', contexts: ['selection'], }); chrome.contextMenus.create({ id: 'majorpoints', title: 'Major Point it', contexts: ['selection'], }); }); chrome.contextMenus.onClicked.addListener(async function (info, tab) { if (info.menuItemId === 'summarize' || info.menuItemId === 'majorpoints') { // Inject the content script chrome.scripting.executeScript( { target:{tabId: tab.id}, function: fetchDataAndInteract, args: [info], }); } }); async function fetchDataAndInteract (info) { chrome.storage.sync.get('openaiApiKey', async function (apiKeyData) { const apiKey = apiKeyData.openaiApiKey; if (!apiKey) { alert('Please set your OpenAI API key in the extension settings.'); return; } const action = info.menuItemId; const selectedText = info.selectionText; const prompt = action === 'summarize' ? `Summarize: ${selectedText}` : `Write the major point of this post: ${selectedText}`; const response = await fetch('https://api.openai.com/v1/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}`, }, body: JSON.stringify({ prompt: prompt, max_tokens: 100, n: 1, stop: null, temperature: 0.3, }), }); const resultData = await response.json(); if (resultData.choices && resultData.choices.length > 0) { const resultText = resultData.choices[0].text.trim(); const resultTitle = action === 'summarize' ? 'Summary:' : 'Major Points:'; chrome.scripting.executeScript({ target: { tabId: tab.id }, function: showResult, args: [resultTitle, resultText], }); } else { console.error('No choices returned from API call.'); } }); } async function showResult(resultTitle, resultText) { const popup = document.createElement('div'); popup.style.position = 'fixed'; popup.style.top = '20%'; popup.style.left = '50%'; popup.style.transform = 'translate(-50%, -50%)'; popup.style.zIndex = '9999'; popup.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'; popup.style.padding = '20px'; popup.style.borderRadius = '10px'; popup.style.maxWidth = '80%'; popup.style.textAlign = 'center'; popup.style.fontFamily = 'Arial, sans-serif'; const title = document.createElement('h3'); title.innerText = resultTitle; title.style.marginBottom = '10px'; popup.appendChild(title); const result = document.createElement('p'); result.innerText = resultText; popup.appendChild(result); document.body.appendChild(popup); setTimeout(function () { document.body.removeChild(popup); }, 10000); }
content.js 文件
//content.js chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { if (request.action === 'showResult') { console.log('Message received in content.js:', request); const { resultTitle, resultText } = request; const popup = document.createElement('div'); popup.style.position = 'fixed'; popup.style.top = '20%'; popup.style.left = '50%'; popup.style.transform = 'translate(-50%, -50%)'; popup.style.zIndex = '9999'; popup.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'; popup.style.padding = '20px'; popup.style.borderRadius = '10px'; popup.style.maxWidth = '80%'; popup.style.textAlign = 'center'; popup.style.fontFamily = 'Arial, sans-serif'; const title = document.createElement('h3'); title.innerText = resultTitle; title.style.marginBottom = '10px'; popup.appendChild(title); const result = document.createElement('p'); result.innerText = resultText; popup.appendChild(result); document.body.appendChild(popup); setTimeout(function () { document.body.removeChild(popup); }, 10000); sendResponse({ success: true }); } // sendResponse({ success: true }); });
popup.js 文件
// popup.js document.addEventListener('DOMContentLoaded', async function () { chrome.runtime.sendMessage({ action: 'processText' }, async function (globalData) { const title = document.getElementById('title'); const result = document.getElementById('result'); if (globalData && (globalData.action === 'summarize' || globalData.action === 'majorpoints')) { const apiKey = globalData.apiKey; const selectedText = globalData.selectedText; const prompt = globalData.action === 'summarize' ? `Summarize: ${selectedText}` : `Major Points of: ${selectedText}`; title.textContent = globalData.action === 'summarize' ? 'Summary:' : 'Major Points:'; result.textContent = 'Loading...'; try { const response = await fetch('https://api.openai.com/v1/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}`, }, body: JSON.stringify({ prompt: prompt, max_tokens: 50, n: 1, stop: null, temperature: 0.7, }), }); const data = await response.json(); const resultText = data.choices[0].text.trim(); result.textContent = resultText; } catch (error) { console.error('Error fetching the summary/Major Point:', error); result.textContent = 'An error occurred. Please try again later.'; } } }); });
popup.html 文件
<!DOCTYPE html> <html> <head> <style> body { width: 300px; height: 200px; font-family: Arial, sans-serif; } </style> </head> <body> <h3 id="title"></h3> <div id="result"></div> <script src="popup.js"></script> </body> </html>
解决建议
1. 错误根源
Could not establish connection. Receiving end does not exist 错误来自popup.js中的chrome.runtime.sendMessage调用——后台脚本(background.js)没有监听processText这个消息类型,导致发送方找不到接收端,触发连接错误。同时代码还存在变量作用域、逻辑冗余等问题。
2. 具体修复步骤
(1)移除popup.js无效的消息发送逻辑
当前扩展通过右键菜单触发功能,popup无需自动请求处理,直接简化popup.js:
// popup.js 简化后 document.addEventListener('DOMContentLoaded', function () { const title = document.getElementById('title'); title.textContent = '选中文本后右键使用功能'; });
(2)修复background.js变量作用域问题
fetchDataAndInteract函数中无法直接访问tab.id,需要把它作为参数传入:
chrome.contextMenus.onClicked.addListener(async function (info, tab) { if (info.menuItemId === 'summarize' || info.menuItemId === 'majorpoints') { chrome.scripting.executeScript({ target: {tabId: tab.id}, function: fetchDataAndInteract, args: [info, tab.id], // 传入tab.id }); } }); async function fetchDataAndInteract (info, tabId) { // ... 原有代码 if (resultData.choices && resultData.choices.length > 0) { // ... 原有代码 chrome.scripting.executeScript({ target: { tabId: tabId }, // 使用传入的tabId function: showResult, args: [resultTitle, resultText], }); } // ... 原有代码 }
(3)修复API请求中的转义字符
background.js里的&&和>是HTML转义字符,要改成JS原生的&&和>:
// 原代码 if (resultData.choices && resultData.choices.length > 0) { // 修改后 if (resultData.choices && resultData.choices.length > 0) {
(4)统一UI展示逻辑
你同时在background.js和content.js中实现了相同的弹窗逻辑,二选一即可:
- 保留background.js的
showResult注入逻辑,直接删除content.js文件; - 若想用content.js展示弹窗,需确保调用
chrome.runtime.sendMessage前已注入content.js。
(5)优化权限配置
把host_permissions改成更精确的OpenAI API地址:
"host_permissions": [ "https://api.openai.com/v1/*" ]
3. 测试验证
- 重新打包扩展并加载到Chrome;
- 选中网页文本,右键点击对应菜单;
- 检查是否弹出结果弹窗,同时查看控制台(F12)是否还有错误。
内容的提问来源于stack exchange,提问作者Reenu
相关产品推荐
相关产品推荐

