场景:网页端文件下载代码迁移至VScode Webview端,使用windows.open(url)方式下载会出现
Blocked opening 'because the request was made in a sandboxed frame whose 'allow-popups' permission is not set.
错误
来看看ChatGPT对此错误的解释
该错误是浏览器的安全限制,指示请求是在一个启用了沙箱的 iframe 中发出的,并且没有设置 "allow-popups"权限,因此被阻止了。
浏览器默认情况下在沙箱 iframe 中禁止弹出窗口,以保护用户免受恶意行为的影响。如果你尝试在沙箱 iframe中打开新窗口或弹出窗口,浏览器会拦截该请求并报告此错误。
因此这里建议用文件传输流进行下载文件,不过为了代码的复用,实现具体下载功能的函数不放在页面端,而应该置于插件入口文件extension.ts
内,实现统一的注册功能和事件处理。
在业务页面代码内,通过调用封装好的vscodeApi.postMessage(),将下载url传递给VScode后端做处理。
this.vscodeApi.postMessage({command: 'download', url: url, fileName: fileName});
在extension.ts内,根据Message的command执行异步下载函数。
import * as fs from 'fs';
import * as http from 'http';
async function download(url: string, fileName: string) {
const downloadPath = 'C:/xxx/xxx/test.log';
const downloadUrl = vscode.Uri.parse(url);
// 创建一个可写的文件流
const file = fs.createWriteStream(downloadPath);
// 打开下载url
http.get(downloadUrl.toString(), (response) => {
// 使用pipe进行文件流传输
response.pipe(file);
// 当所有数据传输完毕,触发“finish"事件
file.on('finish', () => {
file.close();
vscode.window.showInformationMessage('File downloaded successfully!');
});
}).on('error', (err) => {
console.error('Error downloading file:', err);
vscode.window.showErrorMessage('Error downloading file!');
});
}
场景进阶:当使用Remote SSH 远程连接VSCode时候,使用该上述方法下载的文件会在远程端PC上,现在需要将其改在用户本地端。
先上个人结论:在VSCode的WebView端进行的任何操作(即Angualr框架内)都无法脱离VSCode的束缚,即无法和外界浏览器进行交互。因此如果想要直接在用户端实现下载,只能通过Visual Studio Code 的 API。核心代码如下:
import * as vscode from 'vscode';
vscode.env.openExternal(vscode.Uri.parse(url));
这个方法将会在默认的外部浏览器中打开指定的 URL。请注意,此操作将会在外部浏览器中打开,而不是在 VS Code 内部的 Webview 中打开。