我正在做一个角度应用程序,我必须点击一个休息终点并下载作为响应发送的文件,但我不明白如何去做。我有响应标题,如下所示
内容处置:附件;文件名= “Config.zip” 内容类型:多部分/混合;边界= Boundary_25_1816124633_1519993185650 MIME版本:1.0 Transfer-Encoding:chunked
,响应看起来像
- Boundary_25_1816124633_1519993185650内容类型:application / json
{ “配置”:[{},{},{}]} --Boundary_25_1816124633_1519993185650内容类型:application / octet-stream
PKMÛJAä;%RecurrenceEvent_CreateContract_1.jsoníYKoãF¾ÈxÝ0è÷Ã7Mb L&安培;íÝK0Í|CD¬1ðß(J¤HÙ²¼yV'»ÙU¬®úªú«A·ö«åºv〜\ I〜ùöýw³Ù,E«ù
修改
这是我的http电话,它指向后端
return this.http.get(url).map(response => {
// TODO
});
如何下载附加的zip文件?请帮忙。我被卡住了。
答案 0 :(得分:7)
const executeSaveAs = (content) => {
let blob = new Blob([content], {'type': "application/octet-stream"});
saveAs(blob, "downloaded_zip.zip"); // This is from https://github.com/eligrey/FileSaver.js
};
return this.http.get(url, {responseType: 'arraybuffer'}).pipe(executeSaveAs);
我们需要设置预期的响应类型,我们希望将其作为阵列缓冲区'。然后,我们为FileSaver做了常用的事情,即创建一个blob并将其传递给包的saveAs
函数。
根据评论,要求澄清解析多部分响应的各个部分。
标题中定义的边界表示响应的不同部分。每个部分都以行
开头 --boundaryThatIsInTheHeader
我们可以根据边界拆分响应。为此,我们必须首先从头部解析边界。 RegEx到我们这里救援:
let boundaryRegex = new RegExp(/boundary=(\S+)/g);
const header = `Content-Disposition:attachment; filename="Config.zip" Content-Type:multipart/mixed;boundary=Boundary_25_1816124633_1519993185650 MIME-Version:1.0 Transfer-Encoding:chunked`; // As in the question
const boundary = '--' + boundaryRegex.exec(header)[1]; // We obtain the boundary here
现在,我们需要将响应与边界分开作为分隔符。
response.split(boundary);
为此服务器的特定响应返回的值为
[ "", " Content-Type: application/json\n\n {\"config\":[{},{},{}]} ", " Content-Type: application/octet-stream\n\n PKMÛJAä;%RecurrenceEvent_CreateContract_1.jsoníYKoãF¾ÈxÝ0è÷Ã7Mb L&íÝK0ͦCD¬1ðß(J¤HÙ²¼yV'»ÙU¬®úªú«â· ö«åºv~Í~ùöýw³Ù,È«ù"]
注意数组的第二个元素,即JSON。这就是我们想要的!我们现在可以使用简单的RegEx删除额外的数据,即内容类型。如果响应的格式是常量,我们也可以根据索引直接删除它。 zip文件的内容也是如此。
答案 1 :(得分:1)
我相信multipart/mixed
和multipart/form-data
有一些共同的结构。
(不完全确定区别是什么。)
form-data
主要是用于将表单发送到服务器,但也可以反过来使用。
fetch api有一个名为.formData()
的方法这主要与服务人员有关。如果用户提交表单并且服务工作者截获请求,您可以例如在其上调用formData()以获取键值映射,修改某些字段,然后将表单向前发送到服务器(或在本地使用它)
因此,如果我们可以获得响应并将content-type
标题更改为multipart/form-data
,我们可以使用fetch api来读取内容而无需解析它。
getExampleResponse(async res => {
// replace the content-type to multipart/form-data so fetch api can parse it
const type = res.headers.get('content-type')
res.headers.set('content-type', type.replace('mixed', 'form-data'))
// return the response as a formData
const fd = await res.formData()
// console.log(...fd)
console.log(JSON.parse(fd.get('json')))
console.log(fd.get('image'))
const file = fd.get('image')
const link = document.createElement('a')
const image = new Image
link.href = image.src = URL.createObjectURL(file)
link.innerText = 'download ' + (link.download = file.name)
// saveAs(file); // This is from https://github.com/eligrey/FileSaver.js
document.body.appendChild(image)
document.body.appendChild(link)
})
/*
Don't mind this, it's just an example response you are getting...
What you actually want is something like
function getExampleResponse(cb) {
fetch(url).then(cb)
}
*/
function getExampleResponse(e){var a=document.createElement("canvas"),d=a.getContext("2d");d.fillStyle="blue";d.fillRect(0,0,a.width,a.height);a.toBlob(function(b){var a={a:123};var c='--Boundary_25_1816124633_1519993185650\r\nContent-Disposition: form-data; name="json"\r\nContent-Type: application/json\r\n'+("Content-Length: "+JSON.stringify(a).length+"\r\n\r\n");c+=JSON.stringify(a)+"\r\n";c=c+'--Boundary_25_1816124633_1519993185650\r\nContent-Disposition: form-data; name="image"; filename="image.png"\r\nContent-Transfer-Encoding: binary\r\n'+
("Content-Type: "+b.type+"\r\n");c+="Content-Length: "+b.size+"\r\n\r\n";b=new Blob([c,b,"\r\n--Boundary_25_1816124633_1519993185650--\r\n"]);e(new Response(b,{headers:{"Content-Type":"multipart/mixed; boundary=Boundary_25_1816124633_1519993185650"}}))})};
答案 2 :(得分:0)
是的!我找了这么久,应该早点弄明白的。我想我会把它添加到线程中。
var boundIndex = res.headers['content-type'].indexOf('boundary=') + 'boundary='.length;
var bound = '--' + res.headers['content-type'].slice(boundIndex, res.headers['content-type'].length);
var emanData = res.data.split(bound);
我的回复包括 JSON 部分和 Zip 部分,然后可以将其保存到磁盘。
谢谢!
答案 3 :(得分:-1)
您可以使用file-saver包来使代码更清晰。然后是从后端获取数据的服务方法:
getFile(fileName: string): Observable<Blob> {
return this.http.get(`${environment.apiServerUrl}/` + fileName, {responseType: 'blob'})
.catch(error => this.handleErrorResponse() // catch http error);
}
然后在浏览器事件上调用函数
this.service.getFile('filenameInServer.zip')
.subscribe(fileData => FileSaver.saveAs(fileData, 'sugestedFileNameInDownloadDialog.zip'));