像我问的问题已经很少了,我尝试了这些方法,但它们对我不起作用,也许我遗漏了一些东西,因此我提出一个新问题。
我在打字稿应用程序中调用 API,该 API 返回一个对象,该对象有一个包含文件字节数组表示形式的字段。这是响应模型的样子
{
"fileName": "Pokemon.xlsx",
"fileData":"this is the byte array representation of the file",
"fileContent":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
在我的打字稿组件中,我调用 API 并将 JSON 响应转换为响应接口,这个给定的代码是我从其他链接引用的代码
this.pokemonService.getExcel(REQUEST_OBJECT).subscribe((response) => {
if (response) {
const bytes = new Uint8Array(Buffer.from(response.fileData));
const fileBlob = new Blob([bytes], { type: response.contentType });
if (fileBlob.size > 0) {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(file);
link.download = `${response.fileName}`;
link.click();
}
} else {
//show error
}
});
给出的是我将响应投射到的响应接口
export interface PokemonResponse {
fileData: ArrayBuffer;
fileName: string;
contentType: string;
}
上述代码的问题是,当我打开 Excel 时,它显示文件已损坏,
我还尝试使用下面的代码将上面代码中的
fileBlob
转换为File
对象,但结果仍然相同,用excel打开时下载的文件显示为损坏。
const file = new File([bytes], response.fileName, { type: response.contentType });
我注意到的一件事是
ArrayBuffer
包含文件的字符串表示形式(我猜测是 base64),而 API 返回的是字节数组。
我尝试使用 C# 控制台应用程序直接调用 API,在控制台应用程序中,它按预期工作,创建了 Excel 文件,我可以打开并查看数据,而不会出现任何损坏的文件警报。
我觉得我已经接近解决方案了,但我在这里遗漏了一些关于
ArrayBuffer
的东西。请推荐。
编辑:添加 C# 控制台应用程序与打字稿应用程序的字节比较的屏幕截图
控制台应用程序:
这是我在打字稿应用程序中获得的字节的演示,请注意,我正在打印上面代码中显示的
bytes
变量,它是 Uint8Array
,
观察两个字节表示时,似乎字节的顺序不同,我认为
Uint8Array
转换可能会扰乱打字稿中的顺序。
花了一些时间后我解决了这个问题。
我发现我们必须明确提及浏览器应该解析和返回的数据类型,因此在以角度方式从服务返回响应之前,我使用以下代码更新了内容类型
contentType: `data:${response.contentType};base64,`
请注意,
contentType
是PokemonResponse
接口的属性,如上所示。
一旦我这样做了,文件就成功下载了。我认为这已经由浏览器完成了,但我错了。
作为参考,这里是我必须下载文件的完整代码
axios.post<YOUR_RESPONSE_INTERFACE>('YOUR_API_ENDPOINT')
.then((response) => {
const updatedContentType = `data:${response.data.contentType};base64,`
const fileDownloadElement = document.createElement('a');
document.body.appendChild(fileDownloadElement);
fileDownloadElement.download = `${response.data.fileName}`;
fileDownloadElement.href = updatedContentType + response.data.fileData;
fileDownloadElement.setAttribute('style', 'display:none;');
fileDownloadElement.target = '_blank';
fileDownloadElement.click();
document.body.removeChild(fileDownloadElement);
})
.catch((error) => {
console.log(error);
})
希望有帮助。