res.download отправляет файл, как показать окно загрузки в angular.js [duplicate]

Проблема с «context»

Термин «контекст» иногда используется для ссылки на объект, на который это ссылается. Его использование неуместно, потому что оно не подходит семантически или технически с помощью ECMAScript.

ECMAScript это означает обстоятельства, окружающие что-то, что добавляет смысл, или некоторые предыдущие и последующие данные, которые дает дополнительный смысл. Термин «контекст» используется в ECMAScript для ссылки на this , который представляет собой все параметры, область действия и этот в рамках некоторого исполняемого кода.

В показано это :

Задайте значение ThisBinding тем же значением, что и ThisBinding для контекста выполнения вызова

], который четко указывает, что это часть контекста выполнения.

Контекст выполнения предоставляет информацию, которая добавляет смысл исполняемому коду. Он содержит гораздо больше информации, что только thisBinding.

Таким образом, значение этого не является «контекстом», это всего лишь одна часть контекста выполнения. Это, по сути, локальная переменная, которая может быть задана вызовом любого объекта и в строгом режиме для любого значения вообще.

127
задан Scott 30 November 2015 в 17:38
поделиться

7 ответов

Поддержка загрузки двоичных файлов при использовании ajax невелика, она все еще находится в разработке как рабочие черновики .

Простой способ загрузки:

Вы можете загрузить браузер для загрузки запрошенного файла, просто используя приведенный ниже код, и это поддерживается во всех браузерах и, очевидно, вызовет запрос WebApi тот же.

$scope.downloadFile = function(downloadPath) { 
    window.open(downloadPath, '_blank', '');  
}

Метод загрузки бинарных файлов Ajax:

Использование ajax для загрузки двоичного файла может быть выполнено в некоторых браузерах, а ниже - реализация, которая будет работать в самых последних вариантах Chrome, Internet Explorer, FireFox и Safari.

Он использует тип ответа arraybuffer, который затем преобразуется в JavaScript blob, который затем либо предоставляется для сохранения с использованием метода saveBlob - хотя это только сейчас присутствует в Internet Explorer или превращается в URL-адрес данных blob, который открывается браузером, запуская диалог загрузки, если тип mime поддерживается для просмотра в браузере.

Internet Explorer 11 Поддержка (исправлена)

Примечание. Internet Explorer 11 не любил использовать функцию msSaveBlob, если она была псевдонимом - возможно, secu но, скорее, недостаток, поэтому использование var saveBlob = navigator.msSaveBlob || navigator.webkitSaveBlob ... etc. для определения доступной поддержки saveBlob вызвало исключение; поэтому теперь код ниже проверяется отдельно для navigator.msSaveBlob. Благодаря? Microsoft

// Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
$scope.downloadFile = function(httpPath) {
    // Use an arraybuffer
    $http.get(httpPath, { responseType: 'arraybuffer' })
    .success( function(data, status, headers) {

        var octetStreamMime = 'application/octet-stream';
        var success = false;

        // Get the headers
        headers = headers();

        // Get the filename from the x-filename header or default to "download.bin"
        var filename = headers['x-filename'] || 'download.bin';

        // Determine the content type from the header or default to "application/octet-stream"
        var contentType = headers['content-type'] || octetStreamMime;

        try
        {
            // Try using msSaveBlob if supported
            console.log("Trying saveBlob method ...");
            var blob = new Blob([data], { type: contentType });
            if(navigator.msSaveBlob)
                navigator.msSaveBlob(blob, filename);
            else {
                // Try using other saveBlob implementations, if available
                var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
                if(saveBlob === undefined) throw "Not supported";
                saveBlob(blob, filename);
            }
            console.log("saveBlob succeeded");
            success = true;
        } catch(ex)
        {
            console.log("saveBlob method failed with the following exception:");
            console.log(ex);
        }

        if(!success)
        {
            // Get the blob url creator
            var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
            if(urlCreator)
            {
                // Try to use a download link
                var link = document.createElement('a');
                if('download' in link)
                {
                    // Try to simulate a click
                    try
                    {
                        // Prepare a blob URL
                        console.log("Trying download link method with simulated click ...");
                        var blob = new Blob([data], { type: contentType });
                        var url = urlCreator.createObjectURL(blob);
                        link.setAttribute('href', url);

                        // Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
                        link.setAttribute("download", filename);

                        // Simulate clicking the download link
                        var event = document.createEvent('MouseEvents');
                        event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                        link.dispatchEvent(event);
                        console.log("Download link method with simulated click succeeded");
                        success = true;

                    } catch(ex) {
                        console.log("Download link method with simulated click failed with the following exception:");
                        console.log(ex);
                    }
                }

                if(!success)
                {
                    // Fallback to window.location method
                    try
                    {
                        // Prepare a blob URL
                        // Use application/octet-stream when using window.location to force download
                        console.log("Trying download link method with window.location ...");
                        var blob = new Blob([data], { type: octetStreamMime });
                        var url = urlCreator.createObjectURL(blob);
                        window.location = url;
                        console.log("Download link method with window.location succeeded");
                        success = true;
                    } catch(ex) {
                        console.log("Download link method with window.location failed with the following exception:");
                        console.log(ex);
                    }
                }

            }
        }

        if(!success)
        {
            // Fallback to window.open method
            console.log("No methods worked for saving the arraybuffer, using last resort window.open");
            window.open(httpPath, '_blank', '');
        }
    })
    .error(function(data, status) {
        console.log("Request failed with status: " + status);

        // Optionally write the error out to scope
        $scope.errorDetails = "Request failed with status: " + status;
    });
};

Использование:

var downloadPath = "/files/instructions.pdf";
$scope.downloadFile(downloadPath);

Примечания:

Вы должны изменить свой метод WebApi, чтобы вернуть следующие заголовки:

  • Я использовал заголовок x-filename для отправки имени файла. Это удобный пользовательский заголовок для удобства, однако вы можете извлечь имя файла из заголовка content-disposition с помощью регулярных выражений.
  • Вы должны установить заголовок mf content-type для вашего ответа, так что браузер знает формат данных.

Надеюсь, это поможет.

233
ответ дан Scott 21 August 2018 в 11:22
поделиться
  • 1
    Отличный ответ, работал прямо из коробки. Если бы я мог проголосовать более одного раза. Спасибо, Скотт. – Henry 5 October 2015 в 13:58
  • 2
    :-( извините, я пропустил это. BTW это работает очень. Даже лучше, чем filesaver.js – Jeeva Jsb 13 November 2015 в 03:47
  • 3
    Когда я пытаюсь загрузить исполняемый файл Microsoft с помощью этого метода, я возвращаю размер блоба, который примерно в 1,5 раза превышает фактический размер файла. Файл, который загружается, имеет неправильный размер blob. Любые мысли о том, почему это может произойти? Основываясь на взгляде на скрипач, размер ответа правильный, но преобразование содержимого в blob увеличивает его как-то. – user3517454 11 January 2016 в 08:52
  • 4
    Наконец выяснил проблему ... Я изменил код сервера из сообщения, чтобы получить, но я не изменил параметры для $ http.get. Таким образом, тип ответа никогда не устанавливался как arraybuffer, поскольку он передавался как третий аргумент, а не второй. – user3517454 11 January 2016 в 21:55
  • 5
    @RobertGoldwein Вы можете это сделать, но предположение заключается в том, что если вы используете приложение angularjs, вы хотите, чтобы пользователь оставался в приложении, где поддерживается состояние и возможность использования функций после начала загрузки. Если вы перейдете непосредственно к загрузке, нет гарантии, что приложение останется активным, так как браузер не сможет обработать загрузку так, как мы ожидаем. Представьте себе, если на сервере 500 или 404s запрос. Теперь пользователь отключен от приложения «Угловое». Предлагается простейшее предложение об открытии ссылки в новом окне с использованием window.open. – Scott 26 May 2016 в 01:55

Нам также пришлось разработать решение, которое даже работало бы с API-интерфейсами, требующими аутентификации (см. в этой статье )

. Использование AngularJS в двух словах здесь заключается в том, как мы это сделали:

Шаг 1: Создайте специальную директиву

// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
    restrict: 'E',
    templateUrl: '/path/to/pdfDownload.tpl.html',
    scope: true,
    link: function(scope, element, attr) {
        var anchor = element.children()[0];

        // When the download starts, disable the link
        scope.$on('download-start', function() {
            $(anchor).attr('disabled', 'disabled');
        });

        // When the download finishes, attach the data to the link. Enable the link and change its appearance.
        scope.$on('downloaded', function(event, data) {
            $(anchor).attr({
                href: 'data:application/pdf;base64,' + data,
                download: attr.filename
            })
                .removeAttr('disabled')
                .text('Save')
                .removeClass('btn-primary')
                .addClass('btn-success');

            // Also overwrite the download pdf function to do nothing.
            scope.downloadPdf = function() {
            };
        });
    },
    controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
        $scope.downloadPdf = function() {
            $scope.$emit('download-start');
            $http.get($attrs.url).then(function(response) {
                $scope.$emit('downloaded', response.data);
            });
        };
    }] 
});

Шаг 2. Создайте шаблон

<a href="" class="btn btn-primary" ng-click="downloadPdf()">Download</a>

Шаг 3: Используйте его

<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>

Это приведет к синей кнопке. При нажатии на него будет загружен PDF-файл (Внимание: бэкэнд должен доставить PDF-код в кодировке Base64!) И ввести в href. Кнопка станет зеленой и переключит текст на Сохранить . Пользователь может снова щелкнуть и будет представлен стандартный диалог файла загрузки для файла my-awesome.pdf .

2
ответ дан aix 21 August 2018 в 11:22
поделиться

Для меня веб-API был Rails и клиентской стороной Angular, используемой с Restangular и FileSaver.js

веб-API

module Api
  module V1
    class DownloadsController < BaseController

      def show
        @download = Download.find(params[:id])
        send_data @download.blob_data
      end
    end
  end
end

HTML

 <a ng-click="download('foo')">download presentation</a>

Угловой контроллер

 $scope.download = function(type) {
    return Download.get(type);
  };

Угловая служба

'use strict';

app.service('Download', function Download(Restangular) {

  this.get = function(id) {
    return Restangular.one('api/v1/downloads', id).withHttpConfig({responseType: 'arraybuffer'}).get().then(function(data){
      console.log(data)
      var blob = new Blob([data], {
        type: "application/pdf"
      });
      //saveAs provided by FileSaver.js
      saveAs(blob, id + '.pdf');
    })
  }
});
6
ответ дан AnkitG 21 August 2018 в 11:22
поделиться

В вашем компоненте i.e угловой код js:

function getthefile (){
window.location.href='http://localhost:1036/CourseRegConfirm/getfile';
};
0
ответ дан ebo 21 August 2018 в 11:22
поделиться

Вы можете реализовать функцию showfile, которая принимает параметры данных, возвращаемых из WEBApi, и имя файла для файла, который вы пытаетесь загрузить. То, что я сделал, это создать отдельный браузер, который определяет браузер пользователя, а затем обрабатывает рендеринг файла на основе браузера. Например, если целевым браузером является хром на ipad, вы должны использовать javascripts объект FileReader.

FileService.showFile = function (data, fileName) {
    var blob = new Blob([data], { type: 'application/pdf' });

    if (BrowserService.isIE()) {
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    }
    else if (BrowserService.isChromeIos()) {
        loadFileBlobFileReader(window, blob, fileName);
    }
    else if (BrowserService.isIOS() || BrowserService.isAndroid()) {
        var url = URL.createObjectURL(blob);
        window.location.href = url;
        window.document.title = fileName;
    } else {
        var url = URL.createObjectURL(blob);
        loadReportBrowser(url, window,fileName);
    }
}


function loadFileBrowser(url, window, fileName) {
    var iframe = window.document.createElement('iframe');
    iframe.src = url
    iframe.width = '100%';
    iframe.height = '100%';
    iframe.style.border = 'none';
    window.document.title = fileName;
    window.document.body.appendChild(iframe)
    window.document.body.style.margin = 0;
}

function loadFileBlobFileReader(window, blob,fileName) {
    var reader = new FileReader();
    reader.onload = function (e) {
        var bdata = btoa(reader.result);
        var datauri = 'data:application/pdf;base64,' + bdata;
        window.location.href = datauri;
        window.document.title = fileName;
    }
    reader.readAsBinaryString(blob);
}
0
ответ дан Erkin Djindjiev 21 August 2018 в 11:22
поделиться
  • 1
    -1 Добро пожаловать в SO. В коде нет объяснений, это всего лишь кусок кода. :( Вы ссылаетесь на зависимости в своем собственном коде, которые означают, что этот код нельзя использовать без адаптации, например BrowserService. Кроме того, ваши функции, с которыми вы ссылаетесь, имеют неправильное имя. loadReportBlobFileReader вместо loadFileBlobFileReader. url, который вы не используете, если это IE, Chrome или iOS или Android. Установив window на возврат msSaveOrOpenBlob ..., он возвращает boolean. Установка window.document.title после изменения location.href ] В чем смысл? Нужен рефакторинг. – Scott 26 May 2016 в 12:01
  • 2
    Спасибо Скотту за то, что он поймал эти предметы. Я переработал и добавил объяснение. – Erkin Djindjiev 26 May 2016 в 13:09

Отправьте файл как строку base64.

 var element = angular.element('<a/>');
                         element.attr({
                             href: 'data:attachment/csv;charset=utf-8,' + encodeURI(atob(response.payload)),
                             target: '_blank',
                             download: fname
                         })[0].click();

Если метод attr не работает в Firefox, вы также можете использовать метод javaScript setAttribute

1
ответ дан PPB 21 August 2018 в 11:22
поделиться

C # WebApi PDF скачать все, работающие с Angular JS Authentication

Web Api Controller

[HttpGet]
    [Authorize]
    [Route("OpenFile/{QRFileId}")]
    public HttpResponseMessage OpenFile(int QRFileId)
    {
        QRFileRepository _repo = new QRFileRepository();
        var QRFile = _repo.GetQRFileById(QRFileId);
        if (QRFile == null)
            return new HttpResponseMessage(HttpStatusCode.BadRequest);
        string path = ConfigurationManager.AppSettings["QRFolder"] + + QRFile.QRId + @"\" + QRFile.FileName;
        if (!File.Exists(path))
            return new HttpResponseMessage(HttpStatusCode.BadRequest);

        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        //response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
        Byte[] bytes = File.ReadAllBytes(path);
        //String file = Convert.ToBase64String(bytes);
        response.Content = new ByteArrayContent(bytes);
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        response.Content.Headers.ContentDisposition.FileName = QRFile.FileName;

        return response;
    }

Угловая служба JS

this.getPDF = function (apiUrl) {
            var headers = {};
            headers.Authorization = 'Bearer ' + sessionStorage.tokenKey;
            var deferred = $q.defer();
            $http.get(
                hostApiUrl + apiUrl,
                {
                    responseType: 'arraybuffer',
                    headers: headers
                })
            .success(function (result, status, headers) {
                deferred.resolve(result);;
            })
             .error(function (data, status) {
                 console.log("Request failed with status: " + status);
             });
            return deferred.promise;
        }

        this.getPDF2 = function (apiUrl) {
            var promise = $http({
                method: 'GET',
                url: hostApiUrl + apiUrl,
                headers: { 'Authorization': 'Bearer ' + sessionStorage.tokenKey },
                responseType: 'arraybuffer'
            });
            promise.success(function (data) {
                return data;
            }).error(function (data, status) {
                console.log("Request failed with status: " + status);
            });
            return promise;
        }

Угловой JS-контроллер, вызывающий службу

vm.open3 = function () {
        var downloadedData = crudService.getPDF('ClientQRDetails/openfile/29');
        downloadedData.then(function (result) {
            var file = new Blob([result], { type: 'application/pdf;base64' });
            var fileURL = window.URL.createObjectURL(file);
            var seconds = new Date().getTime() / 1000;
            var fileName = "cert" + parseInt(seconds) + ".pdf";
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            a.href = fileURL;
            a.download = fileName;
            a.click();
        });
    };

И последняя страница HTML

<a class="btn btn-primary" ng-click="vm.open3()">FILE Http with crud service (3 getPDF)</a>

Это будет рефакторинг, просто обменяв код, теперь надеемся, что это поможет кто-то, так как мне потребовалось некоторое время, чтобы заставить это работать.

7
ответ дан tfa 21 August 2018 в 11:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: