2

PDF を生成するために、Internet Explorer の URL 制限を回避しようとしています (詳細については、この Microsoft サポート記事を参照してください)。

クライアント側のJSにPDFのバイトストリームを表すbase-64でエンコードされた文字列があります。Firefox と Chrome の場合、先頭に文字列を追加して PDF を表示するdata:application/pdf;base64,と、ブラウザは問題なくデータ URI をレンダリングします。

Internet Explorer の場合、文字列を POST でサーブレットに送り返して、コンテンツ タイプが「application/pdf」のバイト ストリームを返すことができるようにしようとしています。クライアント側のリクエストで実際の PDF コンテンツを渡していることを除いて、次の質問で提案されているソリューションに従っています。

私の HTTP POST は次のようになります。

var pdf; // base-64 encoded string in this variable
$http.post("/convert/pdf", {
    params: {
      base64pdf: pdf
    }
  }, {
    responseType : "arraybuffer"
  }).then( function onSuccess(result) { 
             var file = new Blob([result.data], {type: 'application/pdf'});
             window.navigator.msSaveOrOpenBlob(file, "result.pdf");
           },
           function onFailure() { /* log and do failure case stuff */ });

私のサーバーは Java spring-webmvc サービスを実行しています。Convert コントローラーは次のようになります。

@Controller
@RequestMapping(value = "/convert", produces = "application/pdf")
public class ConvertController {
    @RequestMapping(value = "/pdf", method = RequestMethod.POST)
    public ResponseEntity<byte[]> generatePdf(
        @RequestParam(value="base64pdf", required=true) String base64encodedDataUri,
        HttpServletRequest request) {
      byte[] bytes = Base64.decodeBase64(base64encodedDataUri);

      HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.parseMediaType("application/pdf"));

      String filename = "test.pdf";
      headers.setContentDispositionFormData(filename, filename);
      ResponseEntity<byte[]> response = new ResponseEntity<>(bytes, headers, HttpStatus.OK);
      return response;
    }
    // other methods
}

コントローラーのコードは、この回答に基づいています。問題はないと思います。単体テストで問題なくテストでき、Swagger API インターフェースを介して POST リクエストを送信します。

問題はこれです。$http.postIE でこれをトリガーすると、結果は常にエラー コールバックになり、常にHTTP 400 エラーになります。

私は次のことを観察しました:

  • IE 11 の開発者ツール ネットワーク トラフィック キャプチャを使用して、リクエストが行われていることを確認できます。リクエストには、base-64 でエンコードされた完全で正しい文字列が params に含まれており、これはリクエスト ボディにあります。

  • リクエスト ヘッダーは次のようになります。

Request POST /convert/pdf HTTP/1.1
Content-Type アプリケーション/json;charset=utf-8
application/json、text/plain、*/* を受け入れる
リファラー localhost:8080/
Accept-Language en-US
Accept-Encoding gzip、デフレート
ユーザーエージェント Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) Gecko のような
ホスト localhost:8080
コンテンツの長さ 5699
DNT 1
接続キープアライブ
キャッシュ継続

ロールのキャッシュなし
  • 応答ヘッダーには次のように表示されます。

応答 HTTP/1.1 400 不正な要求
サーバー Apache-Coyote/1.1
アクセス制御許可オリジン *
Access-Control-Allow-Methods POST、GET、OPTIONS、DELETE
Access-Control-Max-Age 360​​0
Access-Control-Allow-Headers x-requested-with
コンテントタイプ申請書/pdf
コンテンツの長さ 98
日付 2015 年 12 月 7 日(月)21:54:32 GMT
接続を閉じる
  • 応答本文に無効な PDF が含まれています。技術的には、開発者ツールはそれをレンダリングできないと言います。保存すると、保存される PDF は有効な PDF ではありません。

  • 編集: Tomcat8 でログを記録したところ、Spring が要求に「base64pdf」パラメーターが欠落していると不平を言っていることがわかりました。

2015-12-08 02:29:32,514 INFO [http-nio-8080-exec-4] INFO Required String parameter 'base64pdf' is not present
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'base64pdf' is not present

だから私は本当に2つの質問があります:

  1. base64pdfどのようにパラメータを失うのですか? パラメータなどに最大長はありますか? data: { base64pdf : pdf }この質問に表示されているオリジナルと、以下のユーザー chenzhenjia によって提案されているように、パラメーターを経由して渡すことの両方を試しました。

  2. この PDF 呼び出しを IE で動作させるにはどうすればよいですか? 一方で、上記で何が間違っているのか知りたいのですが、率直に言って、クライアント側にあるこのbase-64でエンコードされた文字列をPDF. (つまり、これがXY 問題であり、間違ったツリーを鳴らしている場合は、それも知りたいです。)


私は使用しています:

  • AngularJS 1.4.8
  • 春 4.2.3.RELEASE
  • Java 8
  • トムキャット 8
4

3 に答える 3

0

リクエスト本文でbase64pdf文字列を送信することで、これを機能させることができました。

Java で、単純なモデルを作成しました。

public class PayloadHolder {
  private String payload;
  // getters and setters
}

次に、コントローラーのメソッド シグネチャを更新しました。

@RequestMapping(value = "/pdf", method = RequestMethod.POST, produces = "application/pdf")
public ResponseEntity<byte[]> generatePdf(
        @RequestBody(required = true) PayloadHolder payload,
        HttpServletRequest request)

そして最後に AngularJS リクエストを変更しました:

var pdf; // base-64 encoded string in this variable
var request = {
    payload : pdf
};
var config = {
    headers: { 'Accept': 'application/pdf' },
    responseType : "arrayBuffer"
};

$http.post("/convert/pdf", request, config)
      .then( function onSuccess(result) { 
         var file = new Blob([result.data], {type: 'application/pdf'});
         window.navigator.msSaveOrOpenBlob(file, "result.pdf");
       },
       function onFailure() { /* log and do failure case stuff */ });

POST が params を使用して機能しない理由がわかりません。特に、そうすべきではないことを示すドキュメントが見つからなかったためです。これに対処するフォローアップの質問を投稿します。

于 2015-12-08T16:07:20.407 に答える
0

$http.post の場合、サーバー側 (Spring MVC) でリクエスト用の他のコンテンツ タイプを指定していない場合は、コンテンツ タイプを url-form-encoded として設定します。Angular は他のコンテンツ タイプで送信する可能性があるためです。

例:

$http({
method: "post",
url: URL,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $.param({base64pdf: pdf})
}).success(function (result){
         var file = new Blob([result.data], {type: 'application/pdf'});
         window.navigator.msSaveOrOpenBlob(file, "result.pdf");
});
于 2015-12-08T16:22:36.650 に答える
-1

@RequestMappingメソッドの注釈を次のように変更してみてください。

@RequestMapping(value = "/convert", produces = "application/pdf",method = RequestMethod.POST)

または、次の AngularJS POST を試してください。

var req = { method: 'POST', url: 'example.com', headers: { 'Content-Type': 'application/pdf' }, data: { base64pdf: pdf } } 
$http(req).then(function(){...}, function(){...});
于 2015-12-08T01:06:22.347 に答える