Dart and Client Side File Handling (with authorization)

匆匆过客 提交于 2019-12-02 07:13:30

问题


A server side application requires authorization on file download links. This means a normal <a ng-href="{{createLinkToFile()}}"> is no longer sufficient to get enough parameters passed to the server.

When trying to use a programmatic call to the file download, I get the response data back to Dart client application. Using a simple http GET:

    var url = "http://example.com/file";
    headers.putIfAbsent("Authorization", () => "bearer " + token;
    _http.get(url: url, headers : headers);

The future returned by the GET will hold the data, but how do I instruct the browser to download it as a file, instead of just trying to keep it in memory?

Or is there a way to just do it in a normal link?


回答1:


After downloading the data from the server like shown in Using Dart to Download a PNG File (Binary File) and displaying it not working you can create a download link like shown at http://blog.butlermatt.me/2014/03/dynamically-generating-download-files/

import 'dart:html';
void main() {
  List body = [ 'Some test data ...\n'];

  // Create a new blob from the data.
  Blob blob = new Blob(body, 'text/plain', 'native');
  // Create a data:url which points to that data.
  String url = Url.createObjectUrlFromBlob(blob);
  // Create a link to navigate to that data and download it.
  AnchorElement link = new AnchorElement()
      ..href = url
      ..download = 'random_file.txt'
      ..text = 'Download Now!';

  // Insert the link into the DOM.
  var p = querySelector('#text');
  p.append(link);
}



回答2:


The code of Seth solves indeed part of the problem. To make it a bit more complete, I'm now using the following:

void doPdfFileRequest(String url) {  
    var request = new HttpRequest();
    request.open('GET', url);
    request.responseType = "blob";
    request.withCredentials = false;
    request.setRequestHeader("Accept", _httpAcceptHeader);
    request.setRequestHeader("Authorization", "bearer " + token);
    request.onReadyStateChange
        .listen((r) => onData(request, "filename.pdf"));
    request.send();
}

void onData(HttpRequest request, String filename) {
    if (request.readyState == HttpRequest.DONE && request.status == 200) {
      if (!isIE()) {
        var contentType = request.getResponseHeader("content-type");

        AnchorElement downloadLink = new AnchorElement(
            href: Url.createObjectUrlFromBlob(request.response));
        downloadLink.rel = contentType;
        downloadLink.download = filename;

        var event = new MouseEvent("click", view: window, cancelable: false);
        downloadLink.dispatchEvent(event);
      } else {
        var href = Url.createObjectUrlFromBlob(request.response);
        window.open(href, "_self");
      }
   }
}

A few things to notice. Instead of using the downloadLink.click(), a mouse event is constructed to ensure that it works on Firefox as well as on Safari and Chrome. Firefox seems not to handle the click() otherwise. Binding it to the DOM as is done in the code of Seth isn't necessary.

Internet Explorer doesn't understand the download attribute, so nothing will happen, therefore a window.open is used to at least have it work (though not ideal) on IE, it's redirecting to self to avoid being hit by the pop up blocker.

There are solutions that convert the result download result to Base64 first and put it in a data:mimetype href, using the blob this isn't necessary.

A nice way to set the filename on the file to download would be through the content disposition header, but this header is marked as unsafe, so cannot be used. The filename is now set in the code.

Another note, notice that a HttpRequest is used instead http.get(), The HttpRequest allows you to set the responseType, in this case blob, which can be transformed into a object url.



来源:https://stackoverflow.com/questions/29674913/dart-and-client-side-file-handling-with-authorization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!