我在我们的应用程序中添加了一个需要嵌入式pdf查看器的功能。用户将需要能够在访问位于屏幕的另一区域中的一些其他表单的同时查看pdf。
出于安全原因,不接受提供文件网址。相反,视图请求必须转到我们的应用程序,它将提供额外的安全检查。如果检查成功,则pdf作为流返回。永远不能通过浏览器直接访问文件目录。
根据我的阅读,似乎pdf.js应该可以正常使用,因为PDFJS.getDocument方法将接受Uint8数组以及uri。我一直在谷歌搜索其他人如何使用base64ToUint8Array函数解决这个问题。
在客户端,我们使用jQuery和bootstrap,pdf.js和pdf.viewer.js作为页面加载的一部分加载。
这是我当前问题的全部背景,即服务器使用grails并且我不知道如何通过grails控制器类发送二进制pdf数据。
以下是我目前在控制器中的内容:
def view = {
SolutionFile solutionFile = SolutionFile.get(params.sfileId)
InputStream pdfStream = fileStoreService.writeBinary( solutionFile.fileName, solutionFile.file)
pdfStream
}
返回到浏览器的内容是基于我们的核心布局gsp文件生成的html,没有任何包含的模板。我在任何地方都看不到pdf文件数据。
我收到“无效字符”错误字符串包含无效字符'当调用PDFJS.getDocument时,我怀疑返回的响应也不在base64中。
这是html的模型:
这是调用PDFJS的ajax调用:
jQuery(document).ready(function() {
PDFJS.disableStream = true;
PDFJS.disableWorker = true;
function base64ToUint8Array(base64) {//base64 is an byte Array sent from server-side
var raw = atob(base64); //This is a native function that decodes a base64-encoded string.
var uint8Array = new Uint8Array(new ArrayBuffer(raw.length));
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
jQuery('.remote-tab').click(function(e) {
e.preventDefault();
var url = jQuery(this).attr("data-url");
var dataparams = jQuery(this).attr("data-params");
var params;
if (dataparams != null) {
params = JSON.parse(dataparams);
}
var canvasId = jQuery(this).attr("data-loadinto");
jQuery(this.hash).find('#'+canvasId).load(url, params, function(responseTxt, statusTxt, xhr){
console.log("about to call PDFJS");
PDFJS.getDocument(base64ToUint8Array(responseTxt)).then(function(pdfFile) {
PDFJS.disableWorker = true;
var pageNumber = 1;
pdfFile.getPage(pageNumber).then(function(page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var renderContext = {
canvasContext: context,
viewport: viewport
};
canvas.height = viewport.height;
canvas.width = viewport.width;
console.log("rendering page");
page.render(renderContext);
});
});
});
});
});
任何帮助解释我需要做什么,以便将流式PDF正确地返回到ajax函数将非常感激。
答案 0 :(得分:0)
我的基本问题是如何在服务器端向浏览器发送base64编码的二进制文件 用grails编写,特别是如何用grails控制器编写的方法绕过预期的gsp模板生成?
我相信我在这篇文章中找到了解决方案: Writing binary content directly to the client bypassing the Grails view layer
关键是响应缓冲区需要刷新为控制器方法中的最后一个操作,并且必须 在那个控制器方法中完成。
以下是我的控制器方法中的代码:
def view = {
SolutionFile solutionFile = SolutionFile.get(params.sfileId)
response.setContentType("application/octet-stream");
fileStoreService.writeBinary( response, solutionFile.fileName, solutionFile.file)
response.flushBuffer()
}
另一点需要注意的是,必须在写入响应缓冲区之前完成setContentType。我还不确定 得到了正确的内容类型集,但这是故事的另一部分。
返回的结果是base64编码的二进制文件的要求是因为我想使用pdf.js 客户方。具体来说,我想使用PDFJS.getDocument而不是修改提供的viewer.html 文件。 PDFJS.getDocument只接受pdf URI(在这种情况下是不可接受的)或Uint8数组(可以生成 来自base64编码的二进制文件。 )
对于安全性要求,无法在应用程序外部直接访问存储的文件,因此 我们有一个服务,将获取给定文件ID的正确文件。我创建了一个writeBinary方法 返回编码的二进制文件。 (至少我希望如此,仍然在努力。)
void writeBinary( response, fileName, fileId) {
File f=new File(getUrl(fileId))
FileInputStream fis = new FileInputStream(f)
try {
byte[] buf = FileUtils.readFileToByteArray(f)
response.outputStream << buf.encodeBase64()
}
catch (Exception e) {
log.error(e.printStackTrace());
}
finally {
if (fis != null) fis.close()
}
}
所以,我想我已经回答了我最初发布的问题。但是,客户端pdf.js部分仍然无法正常工作 我将继续努力,一旦我弄明白问题就可以问一个新问题。我不会重复使用这个问题,因为我也是这样做的 难以阅读。