Ajaxを使用してPDFファイルをダウンロードして開く


98

PDFを生成するアクションクラスがあります。contentType適切に設定されています。

public class MyAction extends ActionSupport 
{
   public String execute() {
    ...
    ...
    File report = signedPdfExporter.generateReport(xyzData, props);

    inputStream = new FileInputStream(report);
    contentDisposition = "attachment=\"" + report.getName() + "\"";
    contentType = "application/pdf";
    return SUCCESS;
   }
}

私はこれaction をAjax呼び出しで呼び出します。このストリームをブラウザに配信する方法がわかりません。私はいくつかのことを試しましたが、何もうまくいきませんでした。

$.ajax({
    type: "POST",
    url: url,
    data: wireIdList,
    cache: false,
    success: function(response)
    {
        alert('got response');
        window.open(response);
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) 
    {
        alert('Error occurred while opening fax template' 
              + getAjaxErrorString(textStatus, errorThrown));
    }
});

上記はエラーを与えます:

お使いのブラウザが、このサーバーが理解できないリクエストを送信しました。

回答:


37

これには必ずしもAjaxは必要ありません。ただ、<a>あなたが設定している場合、リンクが十分にあるcontent-dispositionattachment、サーバー側のコードで。このようにして、もしそれがあなたの主要な懸念であったなら、親ページは開いたままになります(なぜ、そうでなければ、不必要にAjaxを選択したのでしょうか?)。その上、これを同期してうまく処理する方法はありません。PDFは文字データではありません。バイナリデータです。のようなことはできません$(element).load()。これには完全に新しいリクエストを使用たい。それ<a href="pdfservlet/filename.pdf">pdf</a>は完全に適しています。

サーバー側のコードをさらに支援するために、使用する言語について詳しく伝え、コード試行の抜粋を投稿する必要があります。


7
もう一度:あなたはありません、このためのAjaxを必要としています。困るだけです。PDFはバイナリデータであり、HTMLやJSONのような文字データではありません。
BalusC 2010年

3
var url = contextPath + "/xyz/blahBlah.action"; url + = url + "?" +パラメータ; {var child = window.open(url);を試してください。child.focus(); } catch(e){}
Nayn

5
一部のブラウザでは、window.openは開いたままで空白のままになり、エンドユーザーにとって煩わしい場合があります。したがって、これにはwindow.openも使用しないでください。場合content-dispositionに設定されているattachment、あなただけ取得しますSave as対話を。親ページは変更されません。Just <a href="pdfservlet/filename.pdf">pdf</a>or a <form action="pdfservlet/filename.pdf"><input type="submit"></form>で十分です。
BalusC 2010年

5
URLの長さには制限があります。そして、作者はPOSTについて尋ねています。
Edward Olamisan 2015年

3
@EdwardOlamisanに同意しPOSTます。著者がデータを収集しようとしていたため、これは正解ではありません。
adamj 2016年

122

これが私がこれを機能させた方法です

$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

download.jsを使用した回答の更新

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});


29
それはクロムで動作しますか?空白のPDFしか表示されません。
Tarun Gupta

1
はい、すべての最新のブラウザで動作します。空白のpdfが表示される場合は、新しいタブでajax urlを実行してみてください。そこにも空白の画面が表示される場合は、PDF自体に問題がある可能性があります。PDFファイルが表示され、ダウンロードされたファイルには表示されない場合は、メールでお知らせください。:)
Mayur Padshala

5
これ(アンカー要素)は、IE 11、Edge、Firefoxでは実際には機能しませんでした。成功を「window.open(URL.createObjectURL(blob))」を使用するように変更するだけでうまくいきました。
JimiSweden

3
PDFファイルがダウンロードされましたが、コンテンツがありません。サーバー側でbyte []を保存しており、pdfコンテンツを利用できます。plzが提案します。
Awanish Kumar 2017

4
空のpdfファイルがダウンロードされます。
Farukh

31

元のポスターの問題点を過去の回答で見つけたとは思えません。それらはすべて、投稿者がデータをPOSTし、応答としてダウンロードを取得しようとしたときにGET要求を想定しています。

より良い答えを探す過程で、このAjaxのようなファイルのダウンロードを要求するためのjQueryプラグインが見つかりました。

その「中心」に、入力フィールドとして指定されたデータを含む「一時的な」HTMLフォームを作成します。このフォームはドキュメントに追加され、目的のURLに投稿されます。その直後にフォームが再び削除されます:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

更新 Mayurの回答は、私が参照したjQueryプラグインと比較して、かなり有望で非常にシンプルに見えます。


9

これが私がこの問題を解決する方法です。この投稿
に対するJonathan Amendの回答は、私を大いに助けてくれました。 以下の例は簡略化されています。

詳細については、上記のソースコードは、JQuery Ajaxリクエスト(GET、POST、PUTなど)を使用してファイルをダウンロードできます。また、パラメーターをJSONとしてアップロードし、コンテンツタイプをapplication / json(私のデフォルト)に変更するのにも役立ちます

HTMLのソース:

<form method="POST">
    <input type="text" name="startDate"/>
    <input type="text" name="endDate"/>
    <input type="text" name="startDate"/>
    <select name="reportTimeDetail">
        <option value="1">1</option>
    </select>
    <button type="submit"> Submit</button>
</form>  

2つの入力テキスト、1つの選択およびボタン要素を持つ単純なフォーム。

JavaScriptのページのソース:

<script type="text/javascript" src="JQuery 1.11.0 link"></script>
<script type="text/javascript">
    // File Download on form submition.
    $(document).on("ready", function(){
        $("form button").on("click", function (event) {
            event.stopPropagation(); // Do not propagate the event.

            // Create an object that will manage to download the file.
            new AjaxDownloadFile({
                url: "url that returns a file",
                data: JSON.stringify($("form").serializeObject())
            });

            return false; // Do not submit the form.
        });
    });
</script>  

ボタンをクリックしたときの単純なイベント。AjaxDownloadFileオブジェクトを作成します。AjaxDownloadFileクラスのソースは以下のとおりです。

AjaxDownloadFileクラスのソース:

var AjaxDownloadFile = function (configurationSettings) {
    // Standard settings.
    this.settings = {
        // JQuery AJAX default attributes.
        url: "",
        type: "POST",
        headers: {
            "Content-Type": "application/json; charset=UTF-8"
        },
        data: {},
        // Custom events.
        onSuccessStart: function (response, status, xhr, self) {
        },
        onSuccessFinish: function (response, status, xhr, self, filename) {
        },
        onErrorOccured: function (response, status, xhr, self) {
        }
    };
    this.download = function () {
        var self = this;
        $.ajax({
            type: this.settings.type,
            url: this.settings.url,
            headers: this.settings.headers,
            data: this.settings.data,
            success: function (response, status, xhr) {
                // Start custom event.
                self.settings.onSuccessStart(response, status, xhr, self);

                // Check if a filename is existing on the response headers.
                var filename = "";
                var disposition = xhr.getResponseHeader("Content-Disposition");
                if (disposition && disposition.indexOf("attachment") !== -1) {
                    var filenameRegex = /filename[^;=\n]*=(([""]).*?\2|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1])
                        filename = matches[1].replace(/[""]/g, "");
                }

                var type = xhr.getResponseHeader("Content-Type");
                var blob = new Blob([response], {type: type});

                if (typeof window.navigator.msSaveBlob !== "undefined") {
                    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    var URL = window.URL || window.webkitURL;
                    var downloadUrl = URL.createObjectURL(blob);

                    if (filename) {
                        // Use HTML5 a[download] attribute to specify filename.
                        var a = document.createElement("a");
                        // Safari doesn"t support this yet.
                        if (typeof a.download === "undefined") {
                            window.location = downloadUrl;
                        } else {
                            a.href = downloadUrl;
                            a.download = filename;
                            document.body.appendChild(a);
                            a.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () {
                        URL.revokeObjectURL(downloadUrl);
                    }, 100); // Cleanup
                }

                // Final custom event.
                self.settings.onSuccessFinish(response, status, xhr, self, filename);
            },
            error: function (response, status, xhr) {
                // Custom event to handle the error.
                self.settings.onErrorOccured(response, status, xhr, self);
            }
        });
    };
    // Constructor.
    {
        // Merge settings.
        $.extend(this.settings, configurationSettings);
        // Make the request.
        this.download();
    }
};

このクラスを作成してJSライブラリに追加しました。再利用可能です。お役に立てば幸いです。


2
BlobオブジェクトはIE10 +でサポートされています。
2015年

これを機能させるにresponseTypeは、xhrをに設定するarraybuffer必要がありblobました。(それ以外の場合、これはうまく機能します。)
tjklemz

まったく同じ質問がありました。「リンクにするだけ」と答えた人は全員、OPを助けません。コンテンツが動的であり、リンク先が動的である場合は、それをすべてjqueryする必要があります...私の答えは、すべての非表示の入力(ユーザーには表示されません)を含むフォームをページに配置することでした。それを記入し、jqueryで送信します。よく働く。
スコット

これは素晴らしい答えですが、なぜか空のPDFが壊れてしまいます。それを理解することはできません。私がAPIを介して同じバイトセットを返すとき-それは問題ないので、MVC応答と関係があります。私はFileResult応答タイプを使用します:File(bytes、System.Net.Mime.MediaTypeNames.Application.Octet、fileName);
Jurijs Kastanovs

明確化:アドレスバーからURLを開く場合-ファイルが正しく開かれます。AJAX + blobを使用してファイルを取得すると、ファイルの形式が正しくありません。
Jurijs Kastanovs

7

サーバー関数が取得しているので、私にとってうまくいったのは次のコードです File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:

$http.get( fullUrl, { responseType: 'arraybuffer' })
            .success(function (response) {
                var blob = new Blob([response], { type: 'application/pdf' });

                if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                    window.navigator.msSaveOrOpenBlob(blob); // for IE
                }
                else {
                    var fileURL = URL.createObjectURL(blob);
                    var newWin = window.open(fileURL);
                    newWin.focus();
                    newWin.reload();
                }
});

これは、このコメントの時点で完全に機能し、最新のChrome
Loredra L

6

フォームを作成して送信し、ページから削除するこのプラグインを使用できます。

jQuery.download = function(url, data, method) {
    //url and data options required
    if (url && data) {
        //data can be string of parameters or array/object
        data = typeof data == 'string' ? data : jQuery.param(data);
        //split params into form inputs
        var inputs = '';
        jQuery.each(data.split('&'), function() {
            var pair = this.split('=');
            inputs += '<input type="hidden" name="' + pair[0] +
                '" value="' + pair[1] + '" />';
        });
        //send request
        jQuery('<form action="' + url +
                '" method="' + (method || 'post') + '">' + inputs + '</form>')
            .appendTo('body').submit().remove();
    };
};


$.download(
    '/export.php',
    'filename=mySpreadsheet&format=xls&content=' + spreadsheetData
);

これでうまくいきました。このプラグインはここにあります


このプラグインは、フォームを作成して送信し、ページから削除するだけです。(誰かが疑問に思っていた場合)
2015

4

次のコードは私のために働きました

//Parameter to be passed
var data = 'reportid=R3823&isSQL=1&filter=[]';
var xhr = new XMLHttpRequest();
xhr.open("POST", "Reporting.jsp"); //url.It can pdf file path
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "blob";
xhr.onload = function () {
    if (this.status === 200) {
        var blob = new Blob([xhr.response]);
        const url = window.URL.createObjectURL(blob);
        var a = document.createElement('a');
        a.href = url;
        a.download = 'myFile.pdf';
        a.click();
        setTimeout(function () {
            // For Firefox it is necessary to delay revoking the ObjectURL
            window.URL.revokeObjectURL(data)
                , 100
        })
    }
};
xhr.send(data);

4

PDFのようなストリームデータを取得するためにポストリクエストで空白のPDFの問題を修正するには、リクエストタイプに「arraybuffer」または「blob」として応答タイプを追加する必要があります

$.ajax({
  url: '<URL>',
  type: "POST",
  dataType: 'arraybuffer',
  success: function(data) {
    let blob = new Blob([data], {type: 'arraybuffer'});
    let link = document.createElement('a');
    let objectURL = window.URL.createObjectURL(blob);
    link.href = objectURL;
    link.target = '_self';
    link.download = "fileName.pdf";
    (document.body || document.documentElement).appendChild(link);
    link.click();
    setTimeout(()=>{
        window.URL.revokeObjectURL(objectURL);
        link.remove();
    }, 100);
  }
});

3

Mayur Padshalaによって与えられた答えに関して、これはajaxを介してPDFファイルをダウンロードする正しいロジックですが、他の人がコメントで報告しているように、このソリューションは実際に空白のPDFをダウンロードします。

この理由は、この質問の承認済みの回答で説明されています。jQueryは、まだ一部のHTML5 XHR v2機能を実装していないため、AJAX要求を使用してバイナリデータをロードするときにいくつかの問題があります。この拡張要求とこのディスカッションを参照してください。

したがってHTMLHTTPRequest、コードを使用すると、次のようになります。

var req = new XMLHttpRequest();
req.open("POST", "URL", true);
req.responseType = "blob";
req.onload = function (event) {
    var blob = req.response;
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="name_for_the_file_to_save_with_extention";
    link.click();
}

2

非表示のiframeを作成してから、上記のajaxコードで次のようにします。

URL: document.getElementById('myiframeid').src = your_server_side_url

と削除 window.open(response);


このソリューションは魅力のように機能しました。curl経由でファイルをフェッチするサービスにcurl呼び出しを行うサーバー側スクリプトを呼び出しています。読み込み中のgifをドロップしてリクエストリンクを無効にできるので、これはうまく機能します。
eggmatters 2015

1
このソリューションは、元の投稿のようにPOSTリクエストではなく、GETリクエストで機能します。
チコドロ

2

このスニペットは、同じ問題に直面する角度のあるjsユーザー向けです。応答ファイルは、プログラムされたクリックイベントを使用してダウンロードされることに注意してください。この場合、ヘッダーはファイル名とコンテンツ/タイプを含むサーバーによって送信されました。

$http({
    method: 'POST', 
    url: 'DownloadAttachment_URL',
    data: { 'fileRef': 'filename.pdf' }, //I'm sending filename as a param
    headers: { 'Authorization': $localStorage.jwt === undefined ? jwt : $localStorage.jwt },
    responseType: 'arraybuffer',
}).success(function (data, status, headers, config) {
    headers = headers();
    var filename = headers['x-filename'];
    var contentType = headers['content-type'];
    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);
    }
}).error(function (data, status, headers, config) {
}).finally(function () {

});

答えについて説明をお書きください。
Gufran Hasan

1

Ajaxでそれを行う必要がありますか?それをiframeにロードする可能性はありませんか?


1
これはAjaxで実行できるかどうかを確認しています。技術的に不可能であるか、アプローチが劣っている場合は、他のアプローチに切り替えます。
Nayn

1

これがあなたに数時間を節約し、頭痛からあなたを救うことを願っています。これを理解するのに少し時間がかかりましたが、通常の$ .ajax()リクエストを実行するとPDFファイルが台無しになりましたが、アドレスバーからリクエストすると完全に機能しました。解決策はこれでした:

download.jsを含めます:http : //danml.com/download.html

次に、$。ajax()リクエストの代わりにXMLHttpRequestを使用します。

    var ajax = new XMLHttpRequest(); 

    ajax.open("GET", '/Admin/GetPdf' + id, true); 
    ajax.onreadystatechange = function(data) { 
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                download(this.response, "report.pdf", "application/pdf");

            }
            else if (this.responseText != "")
            {
                alert(this.responseText);
            }
        }
        else if (this.readyState == 2)
        {
            if (this.status == 200)
            {
                this.responseType = "blob";
            }
            else
            {
                this.responseType = "text";
            }
        }
    };

    ajax.send(null);

0

var xhr;
var beforeSend = function(){
    $('#pleasewaitDL').modal('show');
}
$(function () {
    $('#print_brochure_link').click(function(){
        beforeSend();
        xhr = new XMLHttpRequest();
        xhr.open("GET",$('#preparedPrintModalForm').attr('action'), true); 
        xhr.responseType = "blob";
        xhr.onload = function (e) {
            if (this.status === 200) {
                var file = window.URL.createObjectURL(this.response);
                var a = document.createElement("a");
                a.href = file;
                a.download = this.response.name || "Property Brochure";
                console.log(file);
                document.body.appendChild(a);
                a.click();
                
                window.onfocus = function () {                     
                  document.body.removeChild(a)
                }
                $('#pleasewaitDL').modal('hide');
            };
        };
        xhr.send($('#preparedPrintModalForm').serialize());
    });
    $('#pleasewaitDLCancel').click(function() {
        xhr.abort();
    });
});


0

私たちのようにファイルストリーム(物理的に保存されたPDFがないため)で作業する必要があり、ページの再読み込みなしでPDFをダウンロードしたい場合は、次の関数が機能します。

HTML

<div id="download-helper-hidden-container" style="display:none">
     <form id="download-helper-form" target="pdf-download-output" method="post">
            <input type="hidden" name="downloadHelperTransferData" id="downloadHelperTransferData" />
     </form>
     <iframe id="pdf-helper-output" name="pdf-download-output"></iframe>
</div>

Javascript

var form = document.getElementById('download-helper-form');
$("#downloadHelperTransferData").val(transferData);
form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse";
form.submit();

ためにターゲット=「PDF -ダウンロード-出力」、応答はインラインフレームに書き込まれているので、何ページのリロードが実行されませんが、PDF-応答ストリームは、ダウンロードとしてブラウザに出力されます。


申し訳ありませんが、どうすればtransferData値を取得できますか?
ケイト・
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.