【问题标题】:Binary files corrupted - How to Download Binary Files with AngularJS二进制文件损坏 - 如何使用 AngularJS 下载二进制文件
【发布时间】:2017-01-16 09:01:47
【问题描述】:

使用带有角度的 ResponseEntity 下载任何文件都不起作用

我需要在客户端使用 Angular 下载文件, 该文件可以是任何格式,可以是 pdf 或 excel 或图像或 txt ... 我的方法仅适用于 txt 文件,并为我提供了 excel 和图像的失败格式,而对于 pdf,它提供了一个空的 pdf。

所以在我的控制器中,这里是调用服务方法的函数:

    vm.downloadFile = downloadFile;

    function downloadFile(file){
        var urlDir = "C://STCI//"+idpeticion;
        return VerDocServices.downloadFile(file,urlDir)
          .then(function(response) {
            var data = response.data;
            var filename = file;
            var contentType = 'application/octet-stream';//octet-stream             
            var linkElement = document.createElement('a');
            try {
                var blob = new Blob([ data ], {
                    type : contentType
                });
                var url = window.URL.createObjectURL(blob);
                linkElement.setAttribute('href', url);
                linkElement.setAttribute("download", filename);
                var clickEvent = new MouseEvent("click", {
                    "view" : window,
                    "bubbles" : true,
                    "cancelable" : false
                });
                linkElement.dispatchEvent(clickEvent);
            } catch (ex) {
                console.log(ex);
                throw ex;
            }
        }).catch(function(response) {
            alert('Se ha producido un error al exportar del documento');
            console.log(response.status);
            throw response;
        });
    }

我的 service.js 有:

angular.module('mecenzApp').service('VerDocServices',['$http',function($http) {

this.downloadFile = function(file,urlDir) {

    return $http.get('api/downloadFile', {
        params : {
            file : file,
            urlDir : urlDir
        }
    }); }} ]);

而我的服务方式是这样的:

@GetMapping("/downloadFile")
@Timed
public ResponseEntity<byte[]> downloadFile(@RequestParam(value = "file") String file, @RequestParam(value = "urlDir") String urlDir) {
    log.debug("GET ---------------- DOWNLOAD FILE : {}", file);
    log.debug("GET ---------------- From the DIRECTORY: {}",urlDir);

    InputStream fileStream;
    String filepath = urlDir+File.separator+file;
    try {
        File f = new File(filepath);
        log.debug("GET ---------------- FILE: {}",f.getPath());
        fileStream = new FileInputStream(f);
        byte[] contents = IOUtils.toByteArray(fileStream);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/octet-stream"));   
        String filename = file;
        headers.setContentDispositionFormData(filename, filename);
        ResponseEntity<byte[]> response2 = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
        fileStream.close();
        return response2;            
        
    } catch (FileNotFoundException e) {
       System.err.println(e);
    } catch (IOException e) {
        System.err.println(e);
    }
   return null;
}

你能看一下,告诉我我错过了什么吗??

谢谢你:)

【问题讨论】:

    标签: angularjs download angularjs-http


    【解决方案1】:

    如何使用 AngularJS 下载二进制文件

    下载二进制文件时,设置responseType很重要:

    app.service('VerDocServices',['$http',function($http) {
    
        this.downloadFile = function(url, file, urlDir) {
            var config = {
                //SET responseType
                responseType: 'blob',
                params : {
                    file : file,
                    urlDir : urlDir
                }
             };
    
            return $http.get(url, config)
              .then(function(response) {
                return response.data;
            }).catch(function(response) {
                console.log("ERROR: ", response.status);
                throw response;
            }); 
        }; 
    }]);
    

    如果省略responseType,XHR API 默认将UTF-8 编码文本转换为DOMString (UTF-16),这将损坏PDF、图像和其他二进制文件。

    欲了解更多信息,请参阅MDN Web API Reference - XHR ResponseType

    【讨论】:

    • 你真是太棒了!谢谢你uuuuuuuuuuuuuuu:D
    【解决方案2】:

    我对后端不太了解,但我会提供我用过的东西可能会有所帮助,所以关于 Java 脚本文件:

    //your $http(request...)
    
    .success(function (data, status, headers, config) {
      //Recieves base64 String data
      var fileName = 'My Awesome File Name'+'.'+'pdf';
    
      //Parsing base64 String...
      var binaryString =  window.atob(data);
      var binaryLen = binaryString.length;
      var fileContent = new Uint8Array(binaryLen);
      for (var i = 0; i < binaryLen; i++)        {
         var ascii = binaryString.charCodeAt(i);
         fileContent[i] = ascii;
      }
      var blob = new Blob([fileContent], { type: 'application/octet-stream' }); //octet-stream
      var fileURL = window.URL.createObjectURL(blob);
      $sce.trustAsResourceUrl(fileURL);  //allow angular to trust this url
      //Creating the anchor download link
      var anchor = angular.element('<a/>');
      anchor.css({display: 'none'}); // Make sure it's not visible
      angular.element(document.body).append(anchor); // Attach it to the document
      anchor.attr({
        href: fileURL,
        target: '_blank',
        download: fileName
      })[0].click();
      anchor.remove(); // Clean it up afterwards
    })
    //.error(function(...
    

    在您的后端,确保您的 web 服务生成八位字节流并以 base64 数据格式返回文件,我使用 Java JAX-RS 执行此操作,如下所示:

    @POST
    @Path("/downloadfile")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response downloadFile(...){
      String base64String = Base64.getEncoder().encodeToString(/*here you pass your file in byte[] format*/);
      return Response.ok(base64String).build();
    }
    

    【讨论】:

    • 您的回答解决了我的 excel 问题,说它已损坏。我确实尝试过 atob() 但没有 Uint8array 的东西。感谢您分享您的知识。
    猜你喜欢
    • 2021-01-21
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多