Javascript 无法使用angular 6将图像作为zip文件下载

Javascript 无法使用angular 6将图像作为zip文件下载,javascript,angular,typescript,Javascript,Angular,Typescript,这里我有下面这样的动态数据 data = [ "https://dummyimage.com/200x200/000/fff.jpg&text=test", "https://dummyimage.com/200x200/000/fff.jpg&text=testOne", "https://dummyimage.com/200x200/000/fff.png&text=testTwo" ] 点击按钮,我想从这些url中获取所有图像,并将其保存为zip

这里我有下面这样的动态数据

data =  [
  "https://dummyimage.com/200x200/000/fff.jpg&text=test", 
  "https://dummyimage.com/200x200/000/fff.jpg&text=testOne",
  "https://dummyimage.com/200x200/000/fff.png&text=testTwo"
]
点击按钮,我想从这些url中获取所有图像,并将其保存为zip

问题:当我能够以zip格式下载文件并尝试解压缩时,我会遇到错误,因为无法以archieve格式打开image.zip,并且如果我将其另存为单个图像,则图像不会打开,是否有任何方法存储该文件

下面是我的代码

downloadImageData(){


  var blob = new Blob([this.data], { type:  'application/zip'' });

  FileSaver.saveAs(blob,'image.zip');

}
在这里,我有png和jpg以及各种类型的数据,因此链接将获得的任何数据都必须下载为zip文件。angular 5+是否有任何方法。我也在使用filesave包

JS ZIP_车身响应

通过使用http模块,我可以获得以下数据[

  {
    "_body": {

    },
    "status": 200,
    "ok": true,
    "statusText": "OK",
    "headers": {
      "date": [
        "Sun",
        " 25 Nov 2018 12:18:47 GMT"
      ],
      "cache-control": [
        "public",
        " max-age=43200"
      ],
      "expires": [
        "Mon",
        " 26 Nov 2018 00:18:47 GMT"
      ],
      "content-disposition": [
        "attachment; filename=2B.JPG"
      ],
      "content-length": [
        "40649"
      ],
      "server": [
        "Werkzeug/0.14.1 Python/2.7.13"
      ],
      "content-type": [
        "image/jpg"
      ]
    },
    "type": 2,
    "url": "http://some url"
  }
]

我已经创建了一个演示应用程序

注:该代码仅供参考,可能不包括标准编码实践,但可能会指导您创建自己版本的解决方案

我习惯于压缩文件

应用程序模块.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent }  from './app.component';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@NgModule({
  imports:      [ BrowserModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
app.component.ts:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}
从'@angular/core'导入{OnInit,Component};
从'@angular/common/http'导入{HttpClient};
从“JSZip”导入*作为JSZip;
从“文件保护程序”导入{saveAs};
@组成部分({
选择器:“我的应用程序”,
模板:`下载`
})
导出类AppComponent{
构造函数(专用http:HttpClient){
}
下载zip(){
这个。loadSvgData(“https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
这是saveAsZip);
}
私有loadSvgData(url:string,callback:Function):void{
get(url,{responseType:“arraybuffer”})
.subscribe(x=>callback(x));
}
私有saveAsZip(内容:Blob):无效{
var zip=new JSZip.default();
zip.file(“image.svg”,content);
generateAsync({type:“blob”})
.then(blob=>saveAs(blob,'image.zip');
};
}
说明:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}
应用程序只有一个按钮,单击该按钮将使用
HttpClient
从服务器下载图像文件。它将使用
jszip
压缩下载的数据,并使用
文件保护程序将其保存到浏览器


我希望这会有所帮助!

我有点晚了,但这段代码将使用您的图像数组并创建GET请求。之后,它将执行所有请求,并将响应添加到您的zip文件中,然后下载

如果您不喜欢使用fileSaver,我提供了两种下载文件的方法。选择您喜欢的方法

编辑:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}
如果您使用的是旧版本的rxjs,则必须以不同的方式导入
forkJoin
,请参阅rxjs文档。 还要确保您的后端允许下载文件,否则您将出现CORS错误

应用程序组件.ts

import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from 'jszip';

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {

  data = [
    'http://yoururl/file.png',
    'http://yoururl/file2.png'
  ];

  getRequests = [];

  constructor(private _http: HttpClient) {}

  download() {
    this.createGetRequets(this.data);

    forkJoin(...this.getRequests)
     .subscribe((res) => {
      const zip = new JSZip();

      res.forEach((f, i) => {
        zip.file(`image${i}.png`, f);
      });

      /* With file saver */
      // zip
      //   .generateAsync({ type: 'blob' })
      //   .then(blob => saveAs(blob, 'image.zip'));

      /* Without file saver */
      zip
        .generateAsync({ type: 'blob' })
        .then(blob => {
          const a: any = document.createElement('a');
          document.body.appendChild(a);

          a.style = 'display: none';
          const url = window.URL.createObjectURL(blob);
          a.href = url;
          a.download = 'image.zip';
          a.click();
          window.URL.revokeObjectURL(url);
        });
     });
  }

  private createGetRequets(data: string[]) {
    data.forEach(url => this.getRequests.push(this._http.get(url, { responseType: 'blob' })));
  }
}
import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http"; // Different Import
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {

  /* 
    UPDATE 2
    Create a Type map to handle differnet file types 
  */
  readonly MIME_TYPE_MAP = {
    "image/png": "png",
    "image/jpeg": "jpg",
    "image/jpg": "jpg",
    "image/gif": "gif"
  };

  data = [
    "http://url/file.png",
    "http://url/file.jpeg",
    "http://url/file.gif"
  ];

  getRequests = [];

  constructor(private _http: Http) {} // Different Constructor

  download() {
    this.createGetRequets(this.data);

    forkJoin(...this.getRequests).subscribe(res => {
      const zip = new JSZip();
      console.log(res);
      /*
        The return value is different when using the HttpModule.
        Now you need do access the body of the response with ._body,
        as you can see inside the forEach loop => f._body
      */
      let fileExt: String;  // UPDATE 2

      res.forEach((f, i) => {
        fileExt = this.MIME_TYPE_MAP[f._body.type]; // UPDATE 2, retrieve type from the response.
        zip.file(`image${i}.${fileExt}`, f._body);  // UPDATE 2, append the file extension when saving
      });

      zip
        .generateAsync({ type: "blob" })
        .then(blob => saveAs(blob, "image.zip"));
    });
  }

  private createGetRequets(data: string[]) {
    /*
      Change your responseType to ResponseContentType.Blob
    */
    data.forEach(url =>
      this.getRequests.push(
        this._http.get(url, { responseType: ResponseContentType.Blob })
      )
    );
  }
}
app.component.html

<div style="text-align:center">
  <button (click)="download()">Download</button>
</div>
更新:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}
这是一个使用旧的HttpModule的解决方案,我已经尝试过了,它可以正常工作。如果可能的话,我建议换成新的HttpClientModule

更新2:

正如我在评论中所说,您可以在保存文件时更改文件扩展名以处理不同的文件类型。这是一个示例,您可以轻松地扩展此解决方案

应用程序组件.ts

import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from 'jszip';

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {

  data = [
    'http://yoururl/file.png',
    'http://yoururl/file2.png'
  ];

  getRequests = [];

  constructor(private _http: HttpClient) {}

  download() {
    this.createGetRequets(this.data);

    forkJoin(...this.getRequests)
     .subscribe((res) => {
      const zip = new JSZip();

      res.forEach((f, i) => {
        zip.file(`image${i}.png`, f);
      });

      /* With file saver */
      // zip
      //   .generateAsync({ type: 'blob' })
      //   .then(blob => saveAs(blob, 'image.zip'));

      /* Without file saver */
      zip
        .generateAsync({ type: 'blob' })
        .then(blob => {
          const a: any = document.createElement('a');
          document.body.appendChild(a);

          a.style = 'display: none';
          const url = window.URL.createObjectURL(blob);
          a.href = url;
          a.download = 'image.zip';
          a.click();
          window.URL.revokeObjectURL(url);
        });
     });
  }

  private createGetRequets(data: string[]) {
    data.forEach(url => this.getRequests.push(this._http.get(url, { responseType: 'blob' })));
  }
}
import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http"; // Different Import
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {

  /* 
    UPDATE 2
    Create a Type map to handle differnet file types 
  */
  readonly MIME_TYPE_MAP = {
    "image/png": "png",
    "image/jpeg": "jpg",
    "image/jpg": "jpg",
    "image/gif": "gif"
  };

  data = [
    "http://url/file.png",
    "http://url/file.jpeg",
    "http://url/file.gif"
  ];

  getRequests = [];

  constructor(private _http: Http) {} // Different Constructor

  download() {
    this.createGetRequets(this.data);

    forkJoin(...this.getRequests).subscribe(res => {
      const zip = new JSZip();
      console.log(res);
      /*
        The return value is different when using the HttpModule.
        Now you need do access the body of the response with ._body,
        as you can see inside the forEach loop => f._body
      */
      let fileExt: String;  // UPDATE 2

      res.forEach((f, i) => {
        fileExt = this.MIME_TYPE_MAP[f._body.type]; // UPDATE 2, retrieve type from the response.
        zip.file(`image${i}.${fileExt}`, f._body);  // UPDATE 2, append the file extension when saving
      });

      zip
        .generateAsync({ type: "blob" })
        .then(blob => saveAs(blob, "image.zip"));
    });
  }

  private createGetRequets(data: string[]) {
    /*
      Change your responseType to ResponseContentType.Blob
    */
    data.forEach(url =>
      this.getRequests.push(
        this._http.get(url, { responseType: ResponseContentType.Blob })
      )
    );
  }
}
更新3:

import { OnInit, Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import * as JSZip from 'jszip';
import { saveAs } from 'file-saver';

@Component({
  selector: 'my-app',
  template: `<button (click)='downloadZip()'>Download</button>`
})
export class AppComponent {

  constructor(private http: HttpClient) {
  }

  downloadZip() {
    this.loadSvgData("https://c.staticblitz.com/assets/client/icons/file-icons/angular-component-31179578a9a8a16512e9e90ade26549a.svg",
    this.saveAsZip);
  }

  private loadSvgData(url: string, callback: Function) : void{
    this.http.get(url, { responseType: "arraybuffer" })
             .subscribe(x => callback(x));
  }

  private saveAsZip(content: Blob) : void{
    var zip = new JSZip.default();
    zip.file("image.svg", content);
    zip.generateAsync({ type: "blob" })
       .then(blob => saveAs(blob,'image.zip'));
  };
}
从URL中提取文件名的解决方案,这样就不需要文件类型:

import { Component } from "@angular/core";
import { Http, ResponseContentType } from "@angular/http";
import { forkJoin } from "rxjs";
import { saveAs } from "file-saver";
import * as JSZip from "jszip";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  data = ["http://url/file.png", "http://url/file.jpg", "http://url/file.gif"];

  getRequests = [];

  constructor(private _http: Http) {}

  download() {
    this.createGetRequets(this.data);

    forkJoin(...this.getRequests).subscribe(res => {
      const zip = new JSZip();
      let fileName: String;

      res.forEach((f, i) => {
        fileName = f.url.substring(f.url.lastIndexOf("/") + 1); // extract filename from the response
        zip.file(`${fileName}`, f._body); // use it as name, this way we don't need the file type anymore
      });

      zip
        .generateAsync({ type: "blob" })
        .then(blob => saveAs(blob, "image.zip"));
    });
  }

  private createGetRequets(data: string[]) {
    data.forEach(url =>
      this.getRequests.push(
        this._http.get(url, { responseType: ResponseContentType.Blob })
      )
    );
  }
}

您在
'application/zip'
中有3个
'
,这可能是复制错误,但如果您的代码中有它,则应该删除它one@ams这是应用程序中的输入错误我只有2个验证,您是否尝试在不使用FileSaver的情况下下载文件?例如,使用a标记,如果您愿意,我可以提供一个示例。I如果这是您的全部代码,问题是,您必须首先下载二进制数据。您不能简单地添加一个URL数组,并通过提供内容类型使其神奇地成为zip文件。在angular中,您将使用HttpClient下载文件。@ams不,我只尝试使用它,因为我认为它使事情变得简单&确保您可以提供一个示例通过使用上面的urlscan也可以使用http而不是httpClient&我有一个图像数组?在你提到的zip.file(“image.svg”,content)代码中;假设我不知道内容类型jpg或png或text,那么?@Madpop你需要知道文件名,如果不知道,那么你至少需要解析url来确定文件的扩展名(从技术上讲,您可以添加不带扩展名的文件,但用户必须知道可以打开文件的编辑器)@Madpop,您可以修改回调函数,使其在压缩之前等待所有文件下载。顺便问一下,您使用的是哪个版本的angular?我们可以使用http请求吗?因为我现有的项目已经使用http请求,所以如果我放入http客户端模块,它将给出错误,我想right@Madpop对不起,我不明白你的意思你的意思是,你能说得更具体一点吗?Inside
download()
createGetRequest
将从图像数组中创建请求,并将它们推送到
getRequests
中。然后将该数组传递给
forkJoin()
forkJoin
将执行您的请求,其工作原理类似于
Promise.all()
@Madpop给我一秒钟,我会尝试一下确定我使用的http模块,所以如果我放置http客户端模块,那么两者都会有conflict@Madpop是的,您不应该同时使用这两个模块,请选择一个。旧的HttpModule已被弃用,这就是我建议使用新的HttpClientModule的原因。我的解决方案对您有用吗?