Chrome扩展接收Django JSON返回undefined及popup渲染问题排查
问题原因
弹窗显示undefined是三个代码问题导致的:
- 后端返回JSON结构不统一:
- 触发验证码判断时,直接返回字符串类型的URL,不存在
summary字段 - 非验证码分支中,
parsefile()函数最后返回的是Products字典,你在函数里临时定义的带summary字段的data变量根本没有被返回,实际响应里没有summary这个key
- 触发验证码判断时,直接返回字符串类型的URL,不存在
- Manifest V3跨域权限配置错误:你把本地后端地址写在了
permissions数组里,MV3的跨域请求必须把对应域名配置到host_permissions中,否则请求会被浏览器拦截,拿不到正常响应 - 前端没有做响应校验,拿到返回值直接读取
summary属性,只要字段不存在就会返回undefined
另外你原来的通知配置缺少必填的message字段,就算请求成功通知也弹不出来。
修复方案
1. 统一后端返回结构
修改两个后端函数,保证所有分支返回的JSON结构固定,都包含summary字段:
def parsefile(): Products = {} Images = {} # 保留你原有的价格、链接解析逻辑 with open('output1.html', 'r', encoding="utf-8") as f: html_string = f.read() soup = BeautifulSoup(html_string, 'lxml') prices = soup.find_all('a', {'class': 'productOffers-listItemOfferPrice'}) # 提前初始化列表,避免判断key是否存在的冗余逻辑 Products["Website"] = [] Products["Link"] = [] Products["Price"] = [] for elem in prices: oldlink = elem['href'] full_link = "http://XXXX.de" + oldlink Products["Website"].append(full_link) Products["Price"].append(elem.get_text().strip()) Products["Link"].append(full_link) listimage = soup.find('img', {'class': 'datasheet-cover-image'}) Products["Image"] = listimage.get("src") if listimage else "" # 直接返回统一结构,保证summary字段存在 return { 'summary': Products["Image"] if Products["Image"] else f"共找到{len(Products['Price'])}条价格结果", 'raw': 'Successful', 'data': Products } def get_wiki_summary(request): query = request.GET.get('topic', None) +" XXXX" # 保留你原有的UA、爬取、解析逻辑 user_agent_list = [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36', ] user_agent = random.choice(user_agent_list) headers = {'User-Agent': user_agent} search_result_list = list(search(query, tld="de", num=1, stop=1, pause=1)) page = requests.get(search_result_list[0], headers=headers) time.sleep(4) soup = BeautifulSoup(page.text, "lxml") with open("output1.html", "w", encoding="utf-8") as file: file.write(str(soup)) if soup.findAll(text="captcha") : # 验证码分支也返回统一结构 return JsonResponse({ "summary": "触发人机验证,请稍后重试", "raw": "captcha", "data": {"jump_url": search_result_list[0]} }) else: data = parsefile() return JsonResponse(data)
2. 修正Manifest权限配置
把本地后端地址加到host_permissions里,删除无效配置项,保证跨域请求正常:
{ "name": "Price Comparator", "description": "Compare prices across other websites!", "version": "1.0", "manifest_version": 3, "background": { "service_worker": "background.js" }, "icons": { "16": "images/logo16.png", "48": "images/logo48.png", "128": "images/logo128.png" }, "action": { "default_icon": "images/logo16.png", "default_popup": "popup.html" }, "host_permissions": [ "XXX*", "http://127.0.0.1:8000/*" ], "permissions": [ "XXX", "storage", "activeTab", "scripting", "tabs", "identity", "notifications" ], "content_scripts": [ { "matches": [ "https://www.google.com/*" ], "css": [ "main.css" ] } ] }
注意:原来写在permissions里的
http://127.0.0.1:8000/和background是无效配置,直接删掉即可。
3. 优化background.js的请求逻辑
增加错误分支的响应返回,避免前端回调一直挂起:
chrome.runtime.onInstalled.addListener(() => { console.log('Extension is running!'); }); chrome.tabs.onActivated.addListener(function (activeInfo) { chrome.tabs.get(activeInfo.tabId, function (tab) { y = tab.url; console.log("you are here: " + tab.title); }); }); chrome.tabs.onUpdated.addListener((tabId, change, tab) => { if (tab.active && change.url) { console.log("you are here: " + change.url); } }); var serverhost = 'XXXX'; chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { var url = serverhost + '/wiki/get_wiki_summary/?topic=' + encodeURIComponent(request.topic); console.log(url); fetch(url) .then(response => { if (!response.ok) throw new Error(`接口返回状态码${response.status}`); return response.json(); }) .then(response => sendResponse({ farewell: response })) .catch(error => { console.error(error); // 请求出错时也给前端返回固定结构 sendResponse({ farewell: { summary: "请求失败:" + error.message, raw: "error", data: {} } }); }) return true; });
4. 修改popup逻辑,实现数据渲染到页面
首先在popup.html里添加结果展示容器,放在你原来的搜索输入框、按钮下面即可:
<div id="result-area" style="min-width: 300px; padding: 8px;"></div>
然后修改popup.js,增加响应校验、页面渲染逻辑,同时修复通知配置:
$(function(){ $('#keywordsubmit').click(function(){ var search_topic = $('#keyword').val(); if (search_topic){ chrome.runtime.sendMessage( {topic: search_topic}, function(response) { // 先做响应合法性校验 if (!response || !response.farewell) { alert("请求无响应,请检查后端服务是否启动"); return; } const result = response.farewell; alert(result.summary); // 渲染数据到popup页面 const resultContainer = $('#result-area'); resultContainer.empty(); // 渲染商品图 if (result.data.Image) { resultContainer.append(`<img src="${result.data.Image}" style="max-width: 100%; margin-bottom: 8px;">`); } // 渲染价格列表 if (result.data.Price && result.data.Price.length > 0) { const priceList = $('<ul style="padding-left: 20px; margin: 0;"></ul>'); result.data.Price.forEach((price, idx) => { const link = result.data.Link[idx]; priceList.append(`<li style="margin-bottom: 4px;"><a href="${link}" target="_blank">${price}</a></li>`); }); resultContainer.append(priceList); } // 修复通知配置,basic类型必须传message字段 var notifOptions = { type: "basic", iconUrl: "images/logo48.png", title: "价格查询结果", message: result.summary }; chrome.notifications.create('PriceResultNotif', notifOptions); }); } $('#keyword').val(''); }); });
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

