我正在尝试解决 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
所以我真的有两个问题:
我怎么会丢失
base64pdf
参数? 参数有最大长度吗?我尝试了这个问题中显示的原始内容,并按照下面用户 chenzhenjia 的建议通过data: { base64pdf : pdf }
传递了参数。如何让这个 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/