java - PDF 数据的 AngularJS POST 总是失败

标签 java angularjs spring-web

我正在尝试解决 Internet Explorer 的 URL 限制(有关更多信息,请参阅 this Microsoft support article)以生成 PDF。

我的客户端 JS 中有一个 base-64 编码的字符串,代表 PDF 的字节流。对于 Firefox 和 Chrome,我通过在字符串前添加 data:application/pdf;base64, 来显示 PDF,浏览器会愉快地呈现数据 URI。

对于 Internet Explorer,我试图在 POST 中将字符串发送回 servlet,以便它可以返回内容类型为“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 如下所示:

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

Controller 代码基于 this answer .我认为这没有问题;它通过 Swagger API 接口(interface)在单元测试和直接 POST 请求中测试良好。

问题是这样的。每当我在 IE 中触发此 $http.post 时,结果总是错误回调,并且总是 HTTP 400 错误。

我观察到以下情况:

  • 使用 IE 11 的开发人员工具网络流量捕获,我可以观察正在发出的请求。该请求在请求正文中的参数中包含完整且正确的 base-64 编码字符串。

  • 请求 header 如下所示:

Request         POST /convert/pdf HTTP/1.1
Content-Type    application/json;charset=utf-8
Accept          application/json, text/plain, */*
Referer         localhost:8080/
Accept-Language en-US
Accept-Encoding gzip, deflate
User-Agent      Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Host            localhost:8080
Content-Length  5699
DNT             1
Connection      Keep-Alive
Cache-Cont

rol   no-cache
  • The Response header shows this:

Response                     HTTP/1.1 400 Bad Request
Server                       Apache-Coyote/1.1
Access-Control-Allow-Origin  *
Access-Control-Allow-Methods POST,GET,OPTIONS,DELETE
Access-Control-Max-Age       3600
Access-Control-Allow-Headers x-requested-with
Content-Type                 application/pdf
Content-Length               98
Date                         Mon, 07 Dec 2015 21:54:32 GMT
Connection                   close
  • The Response body contains an invalid PDF. Well, technically the developer tools say it can't render it, and when you save it, the PDF that gets saved isn't a valid PDF.

  • EDIT: I turned up logging in Tomcat8 and observed that Spring is complaining that the "base64pdf" parameter is missing from the request:

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

所以我真的有两个问题:

  1. 我怎么会丢失 base64pdf 参数? 参数有最大长度吗?我尝试了这个问题中显示的原始内容,并按照下面用户 chenzhenjia 的建议通过 data: { base64pdf : pdf } 传递了参数。

  2. 如何让这个 PDF 调用在 IE 中工作?虽然一方面我想知道我在上面做错了什么,但坦率地说我很开放到“正确答案”,了解如何将客户端的这个 base-64 编码字符串转换为 PDF。 (也就是说,如果这是一个 XY problem 而我找错了树,我也想知道。)


我正在使用:

  • AngularJS 1.4.8
  • Spring 4.2.3.RELEASE
  • Java 8
  • Tomcat 8

最佳答案

我最终通过在请求正文中发送 base64pdf 字符串来让它工作。

在 Java 中,我创建了一个简单的模型:

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

然后我更新了我的 Controller 的方法签名:

@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 不能使用参数工作,特别是因为我在文档中找不到任何表明它不应该工作的内容。我会发布一个跟进问题来解决这个问题。

关于java - PDF 数据的 AngularJS POST 总是失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34146207/

相关文章:

java - 如果数据库不存在,是否可以使用 Java 代码在 PostgreSQL for Azure 中动态创建该数据库?如果是,怎么办?

java - 操作链

javascript - 使用 AngularJS 组织代码的最佳方式是什么?

java - 如何在 java.validation 约束上国际化 Spring RestController?

Spring-Boot Embedded Tomcat - 生成localhost.log和cataline.out文件

java - Dijkstra算法中的无限循环?

java - 可热完成长时间运行的任务

javascript - 如何编辑源自超链接(<a href> 标记)的 HTTP GET 请求的授权 header

javascript - 在 SPA 站点中保持 2 个导航菜单同步

spring - 无法访问 Tomcat 上已部署的 WAR 文件