[OutSystems]Downloadでブラウザ内にダウンロードしたファイルを表示する


Webアプリケーションからファイルをダウンロードするときに、ローカルに保存する代わりに同じブラウザのタブにコンテンツを表示する方法を検討してみます。

環境

Personal Environment(Version 11.9.0 (Build 16900))
Service Studio(Version 11.8.9)

テストには以下の2種類のブラウザを使いました。ブラウザや設定によっては動作が異なるかもしれません。

  • Chrome Version 85.0.4183.102 (Official Build) (64-bit)
  • Edge バージョン 86.0.622.38 (公式ビルド) (64 ビット)

テストに使うPDFファイルを準備

Resourcesに以下のようにPDFファイルを登録します。
(dummy.pdf)

Traditional Webの場合

Downloadを使った実装方法

Action Flowt中にDownloadを置いて以下のように設定すると、対象ファイルを同じタブに開きます。

Save to DiskプロパティをNoに設定することでブラウザ内にファイルが表示されるように。
ファイルは、Downloadを実行したタブ内に表示してしまうので、

  • Screenを作成し、Preparationでこの処理を実行する
  • 別の画面のリクエストで作成したScreenを新しいタブに開く

とするとよさそうです。

通信内容をチェック

Save to Disk = NoのDownloadを実行すると、HTTP Responseのヘッダーに以下の行が設定されます。

content-disposition: inline; filename="dummy.pdf"

このレスポンスはまさに(OutSystemsとは無関係に)PDFをブラウザ内に表示させるための指示のようです。Qiita内にこの点を説明している投稿がありました。
PDFをブラウザで表示

Reactive Web Appの場合

Downloadに設定箇所がない……

Reactive Web AppのDownloadのパラメータは以下のようになっています。
Save to Diskプロパティがありません。

このまま実行してみると、ファイルを保存するダイアログが出てきて、タブ内に表示はできないようです。

Downloadの実装をチェック

Chromeの検索機能を使って、上記Downloadの処理を追ってみましょう。
Downloadの部分で実行しているJavaScriptは以下の通り。ちなみにこの時点で、Server Actionへの通信(PDFの中身のダウンロード)は終わっています。

OS.Controller.BaseViewController.downloadBinary(downloadPdfVar.value.pdfBinaryOut, "dummy.pdf");

この関数の実体は同じくソースを検索してみると、見えないリンク(Aタグ)を作成し、JavaScriptからクリックさせてファイル保存させているようです。

BaseViewController.downloadBinary = function (content, filename) {
    var blob = content.toBlob() || new Blob([]);
    var link = document.createElement("a");
    link.style.display = "none";
    document.body.appendChild(link);
    if (blob.type) {
        link.type = blob.type;
    }
    var url = window.URL.createObjectURL(blob);
    link.href = url;
    link.download = filename;
    link.click();
    setTimeout(function () { return window.URL.revokeObjectURL(url); }, 500);
    link.remove();
};

Reactive Web Appでブラウザ内にファイル表示するには

残念ながら、デバッガでlink.target = "_blank"にしてもブラウザ内にファイル表示してくれませんでした。それに、せっかくLow-Code製品を使っているのに、あんまり無理やり製品内の動作を上書きするような変更をしたくないですね。

そこで、どうしてもブラウザ内にファイル表示をさせたければ、

  1. Traditional Webで別のモジュールを作成
  2. Screenを作成し、PreparationでSave to Disk = NoのDownloadを配置する
  3. Reactive Web Appから新しいタブで↑のScreenを表示する

という感じでどうでしょうか。セキュリティや業務ロジックのチェックはお忘れなく。