使用javascript从blob:http保存文件,无需重定向

使用javascript从blob:http保存文件,无需重定向,javascript,ajax,image,browser,webclient-download,Javascript,Ajax,Image,Browser,Webclient Download,我已经在SO中介绍了一些建议的解决方案,但没有成功。这就是问题所在。当使用从API端点检索的数据生成blob时,我想强制浏览器下载blob。到目前为止,我已经尝试了三种解决方案,但没有一种有效。代码如下。请注意,为了进一步解释,我在代码中添加了一些注释 const FILE\u NAME\u REGEX=/filename[^;=\n]*=((['“])。?\2|[^;\n]*)/; 导出功能下载(url){ 返回APICall.get(url)。然后(响应=>{ const disposit

我已经在SO中介绍了一些建议的解决方案,但没有成功。这就是问题所在。当使用从API端点检索的数据生成blob时,我想强制浏览器下载blob。到目前为止,我已经尝试了三种解决方案,但没有一种有效。代码如下。请注意,为了进一步解释,我在代码中添加了一些注释

const FILE\u NAME\u REGEX=/filename[^;=\n]*=((['“])。?\2|[^;\n]*)/;
导出功能下载(url){
返回APICall.get(url)。然后(响应=>{
const disposition=response.request.getResponseHeader('Content-disposition');
//^这一行给出了“拒绝获取不安全的标题“内容处置”错误,因此接下来的几行将不会执行,并且不会使用生成锚的部分,而是“else”分支下的代码部分。
if(disposition&&disposition.indexOf('attachment')!=-1){
const matches=FILE_NAME_REGEX.exec(disposition);
if(matches!=null&&matches[1]){
filename=匹配[1]。替换(/['“]/g'”);
}
}
const type=response.request.getResponseHeader('Content-type');
constblob=newblob([response.data],{type});
if(typeof window.navigator.msSaveBlob!=“未定义”){
window.navigator.msSaveBlob(blob,文件名);
}否则{
const URL=window.URL | | window.webkitURL;
const downloadUrl=URL.createObjectURL(blob);
如果(文件名){
常量a=document.createElement('a');
if(a.download的类型===‘未定义’){
window.location=下载URL;
}否则{
a、 href=下载URL;
a、 下载=文件名;
文件.正文.附件(a);
a、 单击();
文件.body.removeChild(a);
}
}否则{
//1.灵魂
window.location=下载URL;
}
设置超时(()=>{
revokeObjectURL(下载URL);
}, 100);
}
});

}
您的代码设置为仅在设置了
文件名
变量时下载文件

仅当您能够读取内容处置标题时(即仅当来源相同时),才设置此变量

因此,简单的解决方法是,当您无法从标题中获取文件名时,为文件名设置一个虚拟值,这样,
filename
总是被设置,您总是尝试下载文件名,而不是在新页面中打开文件名。
更聪明的解决方法是尝试从
url
变量解析文件名,但是如果不知道可能的url的格式,很难为您创建一个

const FILE\u NAME\u REGEX=/filename[^;=\n]*=((['“])。?\2|[^;\n]*)/;
导出功能下载(url){
返回APICall.get(url)。然后(响应=>{
const disposition=response.request.getResponseHeader('Content-disposition');
if(disposition&&disposition.indexOf('attachment')!=-1){
const matches=FILE_NAME_REGEX.exec(disposition);
if(matches!=null&&matches[1]){
filename=匹配[1]。替换(/['“]/g'”);
}
}
如果(!filename){
//getFileNameFromURL(url);
文件名='dummy.png';
}
const type=response.request.getResponseHeader('Content-type');
const blob=新blob([response.data]{
类型
});
if(typeof window.navigator.msSaveBlob!=“未定义”){
window.navigator.msSaveBlob(blob,文件名);
}否则{
const URL=window.URL | | window.webkitURL;
const downloadUrl=URL.createObjectURL(blob);
//如果(文件名){//总是真实的
常量a=document.createElement('a');
if(a.download的类型===‘未定义’){
window.location=下载URL;
}否则{
a、 href=下载URL;
a、 下载=文件名;
文件.正文.附件(a);
a、 单击();
文件.body.removeChild(a);
}
//    }
/*否则就没用了
window.location=下载URL;
}
*/
设置超时(()=>{
revokeObjectURL(下载URL);
}, 100);
}
});
}

以下是关于我发布的问题的发现。实际上有两个问题:

  • 内容处置标题被拒绝,因此没有文件名或处置信息可用。根据@kaido的回复,通过从url中提取文件名并添加“png”来桥接该文件。例如

    const chunks = extendedURl.split('/');
    const pngExtension = '.png';
    const baseName = chunks[chunks.length - 1].split('?')[0];
    filename = `${baseName}${pngExtension}`;
    
  • 更严重的问题是,直到今天我才意识到,当调用axios的Get方法时,responseType并没有设置为“arraybuffer”

    因此,我能够下载“损坏”的文件。这个问题帮助我找出了实际问题所在:

  • 一旦为调用Get方法提供了'responseType:'arraybuffer',文件就开始显示为正常,而不是'break'

    总之,当调用返回FileStreamResult的.net Core Web API端点时,为了能够在FE JavaScript中创建Blob,您应该显式地将responseType设置为“arraybuffer”,如下所示:

    axios.get(extendedURl, { responseType: 'arraybuffer' }).then(response =>...