質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

4回答

30892閲覧

JavaScriptでリクエストをPOSTしてPDF形式のレスポンスをダイレクトに開く方法

ringoing888

総合スコア15

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2016/09/08 06:08

編集2016/09/08 07:55

###前提・実現したいこと

JavaScriptでAPIにJson形式のデータをPOSTして、APIからPDF形式の データを返してブラウザで表示させたいと思っています。ブラウザで表示させる とき、元のリクエスを送出したページはそのままで、PDF用のページを新規で オープンさるという仕様を想定しています。 また、可能なら一時ファイルを作成せずにそのままのレスポンスがダイレクトに PDF表示に繋がるとベストだと思っています。 この時、JavaScriptでAPIにJson形式のデータをPOSTしつつ、新規ページを オープンさせつつ、かつその新規ページはPDFを表示させるという方法について、 この辺りの知見に詳しい方のアドバイスを頂きたいです。 【追記】 「JSON形式のデータをPOSTする」の前段として、<form>なりの要素で可変の 値を受け取り、それをJSON形式に組み直してPOSTしたいです。試した事のところで 長くなるので削除しちゃってますが、JSONdataの中には前段でクリックと同時に formの値をさらって、{ key : value、 key : value } に整形する処理を 入れています。

###試したこと

Jqueryで普通に$.ajaxとかでリクエストするので今色々試してみてます。

$.ajax({ type : 'post', url : '/hoge', data : JSON.stringify(JSONdata), contentType: 'application/JSON', dataType : 'JSON', scriptCharset: 'utf-8', ↓これだとダメなのは解ってるけどどうすれば良いかが解りませんでした。 ※ href.locationを使って、一時ファイルをどこかに作成し、リンク先に 遷移させるとかはやりたくない。 success : function(data) { $("#response").html(JSON.stringify(data)); }, error : function(data) { $("#response").html(JSON.stringify(data)); } });

###補足情報(言語/FW/ツール等のバージョンなど)
想定している環境は以下です。
・Python 2.7.10
・libharu (PDF生成ライブラリ)

【本番】
・PDF生成のAPIをAWSのLambdaで提供
・JSONでデータを与えるとそのデータを差し込んだPDFを返す

【開発環境】
・API部分を簡易に実現する環境としてPythonのFalconを使用
・POSTでJSONを投げる部分はJqueryを使って投げてます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nezume

2016/09/09 06:10

$.ajax を用いて生成した PDF はどのように表示されているのでしょうか?
guest

回答4

0

ベストアンサー

こんな感じでどうでしょう。blob:スキームでURLを生成してます。

<!DOCTYPE html> <html> <head> <title>a</title> <style> div, embed { width: 100%; height: 125vw; } </style> </head> <body> <button id="b1">view pdf</button> <div id="d1"></div> <script> (function() { document.getElementById("b1").addEventListener("click", function() { // ブロックされないようにclickハンドラ内でオープンしとく var previewWindow = window.open("", "preview"); var xhr = new XMLHttpRequest(); xhr.onload = function() { var url = URL.createObjectURL(this.response); // オープンしといた別Windowで表示 previewWindow.location.href = url; // 埋め込んじゃうというのも document.getElementById("d1").innerHTML = '<embed type="application/pdf" src="' + url + '"></embed>'; }; // JSON形式でポストして結果はblobで受け取る xhr.open("POST", "my.pdf"); xhr.responseType = "blob"; xhr.setRequestHeader('Content-Type', 'application/json'); xhr.send('{"hello":"world"}'); }); })(); </script> </body> </html>

投稿2016/09/09 06:23

編集2016/09/09 06:44
guest1213

総合スコア306

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest1213

2016/09/09 07:26

仕様なのかバグなのかはわかりませんがMicrosoft製のブラウザ(IE11, Edge)では動作しませんね。それらのブラウザへの対応は無理そうです。
guest

0

pdfファイルはサイト上においておいてファイルの所在地が返ってくるんじゃなくて
pdfのバイナリーデータが返ってくるんですよね?
であれば単純にtargetをブランクで対象ファイルにpostすればいいのでは?

投稿2016/09/08 06:22

yambejp

総合スコア114505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ringoing888

2016/09/08 07:50 編集

ちょっと、説明が不足してました。まず、JSONでデータを渡すというのはハードコーディングされたものを渡すのではなく、例えばformに入ってる値とかからJSON形式に変換したいんです。 多分、POSTするって以下の様なやり方なのかなと思いますが。。 <a href="javascript:void(0)" onclick="document.test.submit(); return false;" target=_blank>リンク名</a> <form name="test" method="post" action="/hoge"> <input type="hidden" name="value1" value="test1"> <input type="hidden" name="value2" value="test2"> </form> ご提案の方法で確かにそうかもと思ってちょっと考えてみましたが、JSON形式に変換してPOSTっていう処理をどこかで入れないとなんですが、何か方法ありますか?まー、POSTで受けて受け側でPOSTを分解したりとかっていう方法でも実現はできると思うんですが、それってRESTのAPIとしてどうなんだろうという気がしていて。
yambejp

2016/09/09 00:58

単純に <form name="test" method="post" action="/hoge" target="_blank"> ですね。JSON形式のPOSTという言葉に勘違いされているように見えますが 所詮POSTされるのは生データですから 元データをjsonで持っているということであればforで展開して hiddenに展開してからサブミットすればいいでしょう。
ringoing888

2016/09/09 01:08

ご回答有り難うございます。 別の方からの回答への返答にも有りますが、あくまでやりたい事が「JSONリクエストを送出」するという事が重要なので、hiddenに仕込む方法だとやりたい事が実現できないんですよね。 ご存知のように、jsonリクエストをサーバーで受け取ると、リクエストボディに、 { value : hogehoge, value2 : hogehoge } と入って、サーバーに送られてきます。 form要素でpostすると、サーバー側で受け取った時 data=hogehoge という形式で、リクエストボディにパラメータ名(?言い方あってるか不明ですが)=値となって送られてきます。 JSONのリクエストにこだわっているのは、AWSのLambdaはJSONリクエストを純粋に受け付ける仕様のはずなので、できないことはないと思うけど都合が悪そうっていう事と、どうしても前段でパースしてデータ整形する処理が必要になりそうで、それだと不格好なのでなにか良いほうがないかをこちらで聞いてみたという経緯です。
guest

0

私の今やっているwebサービスで、半年前ほどに実装しました(私は指示だけで実際に実装したのは他のメンバですが…)

APIはレスポンスヘッダをContent-Type:application/pdfで返し、
レスポンス本文にpdfのバイナリをそのまま渡します

フロントエンドでは、ダウンロードみたいなボタンがaタグになってまして、
aタグのhrefに上記のAPI(pdfバイナリを返す)を指定し、targetは_blankとしています

で、ダウンロードボタンを押すと、別ウインドウでpdfが開くようになってます

投稿2016/09/09 04:29

EKD

総合スコア161

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EKD

2016/09/09 04:38

ん?なんだか違うところが問題となっているようですね… data = { hoge: xxx, hogehoge: yyy }; data = JSON.stringify(inData); $.ajax({ type: POST, contentType: application/json, data: data, (省略) } でPOSTでajaxできないですかね? リクエストとレスポンスは全く別物です リクエストがjsonだからといって、レスポンスは自由にサーバ側で設定できるはず
ringoing888

2016/09/09 04:39

ご回答有難うございます!実装されてる方が居るのは心強いっすね。 そのPDFバイナリを返すAPIって、APIリクエスト時にパラメータを渡して動的にPDFを生成してる感じですか?パラメータはformのクエリパラメータでしょうか?JSONリクエストで送ったりしてますか? ちなみに、PDFのバイナリってサーバー上で中間ファイル生成してそれを読み込んでます?それともバッファか何かに溜めたPDFデータを創出してますか?実はPDFの送出側でも自分が使ってるlibharuでどうやるのか若干詰まってまして(苦笑) 何か参考情報展開頂けたら嬉しいです。
ringoing888

2016/09/09 04:48 編集

すいません。リクエストとレスポンスが若干言葉の使い方統一されてなくて(←というか間違って使っていて)混乱させてしまってる所あるかもしれませんね。。 もちろんリクエストとレスポンスの話は理解しています。話はもう少しややこしい話でして、リクエスト送出時にJSON形式でデータを送りたいのです。で、リクエストBodyにjson形式でデータを埋め込んで、サーバーにリクエストを送りたいのですが、これはもちろん$.ajaxでdataにjson形式指定すれば送れます。 ただ、それだと非同期通信になってしまい新規ウィンドウを開くという操作を指定できない(ような気がする。調べた限りそういうオプションとか無い。$.ajaxには)というのが問題です。 新規ウィンドウを立ち上げる所にフォーカスすると、既出の_targetとか使えば出来そうですが、submit使うとリクエストBodyにJSON形式でデータを仕込むって方法がなく、 $.ajax使うとJSON形式のリクエストは送出出来るけど新規ウィンドウを開いてPDFを表示させるというのが出来ないって言う所で、方法を模索しています。
EKD

2016/09/09 04:56

私どもの実装ですと、 サーバはバックエンドで定期的にpdfファイルを作成していて、サーバはpdfファイルを大量に保持しています。 ユーザが画面UIから日時などを設定してダウンロードボタンを押すと、 画面UIで選択されている日時などを取得し、動的にjsonパラメータを作成し、APIを呼び出します。 サーバ側は渡されたjsonパラメータを見て、大量のpdfファイルの中から一致するpdfファイルのバイナリをフロントエンドへ返します 残念ながら、APIの中で動的にpdf作成はしていないです 実装はjavaのサーブレットです ちなみにバックエンドでは、pdf作成用のwebページを持っていまして、 wkhtmltopdfというツールを利用してpdf作成しています 参考になるかわかりませんが… 動的なpdf作成APIの実装というのも技術的には可能と思います pdf作成処理が重くなければですが
EKD

2016/09/09 04:58

同期非同期の件だけですと、 $.ajax({ async: false, }) でいけるかと思います
guest

0

form要素にtarget属性を付けるとかでしょうか。

【HTMLタグ/フォームタグ/結果が表示されるウィンドウを指定する - TAG index Webサイト】
http://www.tagindex.com/html_tag/form/form_target.html

【フォームから別ウィンドウを開く方法のまとめ: 小粋空間】
http://www.koikikukan.com/archives/2010/12/20-005555.php

POST前にJSON化せずに受け取った変数をPython側でJSONにするのが手早い気がしますが、submitイベントを拾って書き換える事も可能です。

【【jQuery】submit前に処理を行う方法 - Qiita】
http://qiita.com/kazu56/items/cdbf4e371cdc699709f1

投稿2016/09/08 16:16

kei344

総合スコア69357

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ringoing888

2016/09/08 18:53

ご回答有難うございます。 はい。1番目の方のご回答いただいて、別ウィンドウに開くのにtarget属性でいけそうというのは、お陰さまでクリアになったんですが、やはり「submit前に処理を行う」という方法でもどうやってjsonリクエストを送れば良いのかが不明でして。 多分普通にform要素を使おうとするとサーバー側で受け取るとどうしても、 data=hogehoge というように、パラメータ名(?言い方あってるか不明ですが)=値となってしまい、いわゆるjsonリクエストとは違った形式になりそうです。 jsonリクエストをサーバーで受け取ると、レスポンスのbodyに { value : hogehoge, value2 : hogehoge } と入って送られてくると思うのですが、form要素でpostしようとするとどうしても前段でパースでデータ整形する処理が必要になるかと。。 それか、自分が知らないだけでsubmitの時にbodyにデータを突っ込む方法とかあるんですかね。。 >POST前にJSON化せずに受け取った変数をPython側でJSONにするのが手早い気がしますが、submitイベントを拾って書き換える事も可能です。 まーもっともですね。ただ結局もっとより良い自分が知ってるよりもベターな形で対応する方法が有るんじゃないかと思い質問させて頂いているので。。そもそも論というか実現できれば良い方法ではなく、ベストを探りたく。。 ご丁寧に回答有り難うございます。
kei344

2016/09/08 18:58

「submitイベントを拾って書き換える事も可能です。」は、「submitの時にbodyにデータを突っ込む方法とかある」という意味ですよ。
ringoing888

2016/09/08 19:06

おお。そうなんですね。 jQueryは触ったり離れたりであんまり良く解ってないんですが、リクエスト送出時のボディに値を埋め込む方法ってどうやるんでしょうか?
kei344

2016/09/08 19:37

すいません、「JSONリクエスト」を勘違いしていました。レスポンスボディがJSONなんですね。それであればAjaxで投げる以外に方法は無いと思います。submitイベント時にフォームから値を取り出してJSON化して、質問文に書かれているようなコードで送信、PDFがURLで返ってくるならそこに location.href で移動ですかね。バイナリで返ってくるならjQueryではちょっと難しいかもしれません。 【kintoneで外部APIからPDF帳票をダウンロードする - Qiita】 http://qiita.com/yukinagae/items/9e64d8ad93c65584bee9#_reference-a212c6972da950562fca
ringoing888

2016/09/08 19:43

夜分遅く迄ご丁寧に有難うございます。 あーやはりそうですか。。 やはり一旦テンポラリにPDFファイルを生成して、そのリンクを開くみたいな方法しかないんですかね。。ちょっと他に良い方法がないか、別の方法も検討してみようと思います。 ご丁寧に有難うございました。
kei344

2016/09/09 05:16

> 一旦テンポラリにPDFファイルを生成して、そのリンクを開くみたいな方法しかない バイナリを(サーバ上でテンポラリを作らず)に開くことは出来ます。 【JavaScriptでファイルダウンロード処理を実現する - Qiita】 http://qiita.com/wadahiro/items/eb50ac6bbe2e18cf8813
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問