如何开发Chrome扩展下载Struts框架流式传输的PDF文件?
解决方案:Chrome扩展一键下载流式PDF
核心逻辑
页面里的embed元素源是Data URI(格式为data:application/pdf;base64,...的长字符串),本质是Base64编码的PDF内容。我们只需要提取该编码内容,解码后生成PDF文件并触发浏览器下载即可。
扩展实现步骤
1. 搭建扩展基础结构
创建以下核心文件:
manifest.json:扩展配置文件content.js:注入目标页面的脚本,负责提取PDF编码内容popup.html:扩展弹窗,提供一键下载入口
manifest.json 配置示例
{ "manifest_version": 3, "name": "流式PDF下载器", "version": "1.0", "permissions": ["activeTab", "downloads"], "content_scripts": [ { "matches": ["*://你的系统域名/*.action"], "js": ["content.js"] } ], "action": { "default_popup": "popup.html", "default_icon": { "16": "icon16.png", "48": "icon48.png" } } }
注意:替换你的系统域名为实际系统域名,图标文件可自行准备或省略
2. 编写内容脚本(content.js)
负责定位embed元素并提取Base64编码的PDF内容:
// 提取PDF的Base64编码内容 function getPdfBase64() { const embed = document.querySelector('embed'); if (!embed || !embed.src.startsWith('data:application/pdf;base64,')) { return null; } return embed.src.split('base64,')[1]; } // 监听来自弹窗的下载请求 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'downloadPdf') { const pdfBase64 = getPdfBase64(); if (pdfBase64) { sendResponse({success: true, base64: pdfBase64}); } else { sendResponse({success: false, message: '未找到可下载的PDF内容'}); } } });
3. 实现弹窗页面(popup.html)
提供可视化的下载按钮,并处理下载逻辑:
<!DOCTYPE html> <html> <head> <style> body {width: 150px; padding: 10px; margin: 0;} button {width: 100%; padding: 8px; cursor: pointer; border: none; border-radius: 4px; background: #0078d4; color: #fff;} </style> </head> <body> <button id="downloadBtn">下载PDF</button> <script> document.getElementById('downloadBtn').addEventListener('click', async () => { const [tab] = await chrome.tabs.query({active: true, currentWindow: true}); const response = await chrome.tabs.sendMessage(tab.id, {action: 'downloadPdf'}); if (response.success) { // 将Base64转为Blob对象 const byteChars = atob(response.base64); const byteNumbers = new Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteNumbers[i] = byteChars.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const pdfBlob = new Blob([byteArray], {type: 'application/pdf'}); // 生成临时URL并触发下载 const tempUrl = URL.createObjectURL(pdfBlob); chrome.downloads.download({ url: tempUrl, filename: '文档.pdf', saveAs: true }, () => { URL.revokeObjectURL(tempUrl); // 释放临时资源 }); } else { alert(response.message); } }); </script> </body> </html>
替代方案:右键菜单触发下载
如果不需要弹窗,可添加右键菜单选项:
- 在
manifest.json中更新权限和后台脚本配置:
"background": { "service_worker": "background.js" }, "permissions": ["activeTab", "downloads", "contextMenus"]
- 创建
background.js:
chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create({ id: 'downloadPdf', title: '下载当前PDF', contexts: ['page'] }); }); chrome.contextMenus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === 'downloadPdf') { const response = await chrome.tabs.sendMessage(tab.id, {action: 'downloadPdf'}); if (response.success) { const byteChars = atob(response.base64); const byteNumbers = new Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteNumbers[i] = byteChars.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const pdfBlob = new Blob([byteArray], {type: 'application/pdf'}); const tempUrl = URL.createObjectURL(pdfBlob); chrome.downloads.download({ url: tempUrl, filename: '文档.pdf', saveAs: true }, () => { URL.revokeObjectURL(tempUrl); }); } else { alert('未找到可下载的PDF内容'); } } });
注意事项
- 若embed的src是Blob URL而非Data URI,需调整提取逻辑,通过
fetch获取Blob内容 - 测试时需在Chrome扩展管理页面开启「开发者模式」,加载已解压的扩展文件夹
- 可根据页面标题动态生成文件名,替换代码中的
文档.pdf即可
内容的提问来源于stack exchange,提问作者Spike Colman




