web-dev-qa-db-ja.com

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

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;
   }
}

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

$.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));
    }
});

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

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

86
Nayn

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

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

35
BalusC

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

$.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>")
});
114
Mayur Padshala

過去の回答のどれもが元のポスターの問題を見つけたとは本当に思いません。それらはすべて、ポスターがPOSTデータを試みて応答としてダウンロードを取得しようとしたときにGETリクエストを想定しています。

より良い答えを探す過程で、これを見つけました AjaxのようなファイルのダウンロードをリクエストするためのjQueryプラグイン

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

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

UpdateMayurの答えは、私が言及したjQueryプラグインと比較すると、かなり有望で非常に単純に見えます。

30
chiccodoro

これは私がこの問題を解決する方法です。
この投稿 に関する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 pageソース:

<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 class source:

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ライブラリーに追加しました。再利用可能です。それが役に立てば幸いです。

9

サーバー関数が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();
                }
});
5
ParPar

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

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
);

これは私のために働いた。このプラグインを見つけました こちら

5
Ijas Ameenudeen

ポストリクエストの空白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
Ninja

このスニペットは、同じ問題に直面するangular 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 () {

});
2
Gihan Sandaru

非表示のiframeを作成してから、上記のajaxコードで:

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

window.open(response);を削除します

2
qalhat

次のコードは私のために働いた

//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);
2
MemZ

Ajaxを使用する必要がありますか? iframeにロードする可能性はありませんか?

1
Emil Vikström

これで数時間節約でき、頭痛から解放されることを願っています。これを理解するにはしばらく時間がかかりましたが、通常の$ .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);
1

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

この理由は、この受け入れられた回答で説明されています question :jQueryにはAJAXリクエストを使用してバイナリデータを読み込む際にいくつかの問題があります。HTML5XHR v2機能をまだ実装していないためこの拡張機能 request およびこの discussion を参照してください。

したがって、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();
}
1
Vpant
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
POGSNET

私たちのようにファイルストリームを操作する必要があるため(物理的に保存された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();

target = "pdf-download-output"のため、応答はiframeに書き込まれるため、ページのリロードは実行されませんが、pdf-response-streamはブラウザーにダウンロードとして出力されます。

0
George Maharis