(eXist 4.4,XQuery 3.1)
我向用户提供下载PDF文档的能力,这些文档在请求时动态创建。请求有两个参数:文档名称(即doc=MS609-0002.pdf)和文档语言版本(即lang=EN)。
输出在download.xql中的函数
declare function download:download($node as node(), $model as map(*), $doc as xs:string, $lang as xs:string)
{
...
return response:stream-binary($pdf,"application/pdf", $filename)
}例如,它在IDE中的直接调用和通过eXist模板调用函数中都输出PDF罚款:
http://localhost:8081/exist/apps/deheresi/download?doc=MS609-0002.pdf&lang=EN
然而,使用HTML意味着打开另一个浏览器窗口。
相反,我想要求从按钮上得到休息。我已经看过eXist REST 文档了,我无法让它开始工作。
根据文档,我应该发布一个GET结构如下:
http://localhost:8081/exist/rest/db/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN但当我提出这个要求时,我会得到:
HTTP ERROR 404
Problem accessing /exist/rest/db/deheresi/download.xql.
Reason: Document /db/deheresi/download.xql not found与/exist/rest/apps/:http://localhost:8081/exist/rest/apps/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN的这种变化
返回具有空白树的下列消息:
This XML file does not appear to have any style information associated with it. The document tree is shown below.和/exist/db/apps/:http://localhost:8081/exist/db/apps/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN的这种变化
返回:
XQueryServlet Error
Error found
Message: Cannot read source file
/Applications/eXist-db.app/Contents/Resources/eXist-db/webapp/db/apps/deheresi/download.xql我测试过文件权限,似乎没有问题。虽然可能有REST权限/配置要求,但我不知道?在localhost上REST有问题吗?
编辑:这是应该处理REST请求的全部功能:
xquery version "3.1";
module namespace get="/db/apps/deheresi/modules/download”;
declare namespace templates="http://exist-db.org/xquery/templates";
declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";
import module namespace xslfo = "http://exist-db.org/xquery/xslfo";
import module namespace document="/db/apps/deheresi/modules/document" at "/db/apps/deheresi/modules/document.xql";
import module namespace document-view="/db/apps/deheresi/modules/document-view" at "/db/apps/deheresi/modules/document-view.xql";
import module namespace document-preprint="/db/apps/deheresi/modules/document-preprint" at "/db/apps/deheresi/modules/document-preprint.xql";
import module namespace document-print="/db/apps/deheresi/modules/document-print" at "/db/apps/deheresi/modules/document-print.xql";
import module namespace functx="http://www.functx.com" at "/db/apps/deheresi/modules/functx.xql";
import module namespace globalvar="/db/apps/deheresi/modules/globalvar" at "/db/apps/deheresi/modules/globalvar.xqm";
declare function download:download($doc as xs:string?, $lang as xs:string?)
{ (: parse $doc to get name of XML to transform, send back pdf with same name :)
let $docset := upper-case(substring-before($doc,"."))
let $filename := concat($docset,".pdf")
let $document := doc(concat($globalvar:URIdata,concat($docset,".xml")))
let $language := if (lower-case($lang) = "fr")
then lower-case($lang)
else "en"
let $filename := concat($docset,".pdf")
(: get XSLT stylesheet :)
let $fostylesheet := document-print:single-doc-fo-stylesheet($language)
(: get XEP FO config:)
let $config := util:expand(doc("/db/apps/deheresi/xep.xml")/*)
(: get xml for transformation in correct language :)
let $xml := document-preprint:single-doc-preprint($document, $language)
(: create FO xml :)
let $fo := util:expand(transform:transform($xml, $fostylesheet, ()))
(: render pdf :)
let $pdf := xslfo:render($fo, "application/pdf", (), $config)
return response:stream-binary($pdf,"application/pdf", $filename)};
注:我在这方面做了大量的工作,希望收到一个响应,它将遍历REST的输入和输出函数,并举例说明如何获得一个自发生成的PDF。这包括可能影响REST请求的任何配置/权限问题。
发布于 2018-12-24 20:37:35
由于您在调用以下内容时返回了PDF:
http://localhost:8081/exist/apps/deheresi/download?doc=MS609-0002.pdf&lang=EN
也许,你应该做的是处理这个反应。一个简单的例子是在jQuery中使用FileSaver.js。(您可以谷歌FileSaver.js并下载并将其包含在jQuery页面中):
function preview_cover(path){
var pdffilename="cover.pdf";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
saveAs(this.response, pdffilename);
}}
xhr.open('GET', 'cover-formatter.xq?cover=' + path + '&page_width=' + page_width + '&page_height=' + page_height);
xhr.setRequestHeader('Authorization','Basic ' + sessinfo);
xhr.responseType = 'blob';
xhr.send();
}以上示例将使用现代浏览器(Chrome、Firefox、Edge)下载PDF。
后面的代码是这样的(我剪掉了所有其他东西,只留下了格式化部分):
let $fo := if ($territory = 'WALES') then util:expand(transform:transform($doc, doc("/db/EIDO/data/edit/xsl/EIDOcoverbilingual.xsl"), $parameters))
else util:expand(transform:transform($doc, doc("/db/EIDO/data/edit/xsl/EIDOcover.xsl"), $parameters))
let $pdf := xslfo:render($fo, "application/pdf", (), $config)
let $headers := response:set-header("Content-Disposition", "attachment;filename=document.pdf")
return
response:stream-binary($pdf, "media-type:application/pdf","document.pdf")下面是一个更长的jQuery Javascript代码,它试图在Javascript端处理响应。有几个小窍门要注意,我要先提一下,以便理解。一个问题是iOS或IE9浏览器无法处理浏览器中的二进制下载。因此,服务器端代码实际上有一个创建PDF的黑客,如果浏览器是iE9或iOS,它会将结果存储在DB (或AWS S3)中,并返回到该PDF的链接,以便“单击”查看。如果正确执行,其他普通浏览器可以自动处理发送回的二进制数据。为此,我们使用下载PDF的FileSaver.js插件Javascript。
坦白地说,你可以忽略其他的部分。就像将事件发送到Google的logEvent一样,totformats变量跟踪用户的下载,并在任何一个会话中限制用户下载。Chrome下载的黑客攻击可能并不是必需的,因为这是Android Chrome中的一个缺陷。添加和加载“加载器”类是用于GUI的。使用IP作为变量设置的iE9,iOS解决方案,这是因为数据库在许多国家被复制和负载平衡,而且由于数据是为这一次调用写入DB的,所以我们需要有结果的确切服务器的IP地址。这将随着S3集成而消失。
本质上,关键是调用相同的URL,并使用以下方法保存响应:
saveAs(this.response, pdffilename);这是对FileSaver.js的调用,它处理从XHR保存二进制数据并为您下载二进制数据。我从一个更大的代码中删掉了这一点,它处理了所有的下载,包括从RenderX动态生成的下载,就像您的代码一样,但也包括静态PDF。
这个调用很简单,只是一个到达customer-formatter.xq (在我的例子中,这与调用http://localhost/customer-formatter.xq是一样的)(因为我去掉了/exist,我在Jetty的文章是80):
xhr.open('GET', 'customer-formatter.xq?masterlang=' + masterlang + '&doclang=' + doclang + '&specialty='+ specialty + '&article=' + docnum + '&user_name=' + loggedInUser + '&territory=' + territory + '&expiry=' + expiry + '&page_width=' + page_width + '&page_height=' + page_height + '&column_count=' + column_count + '&phrasechange=' + phrasechange + '&genlink=' + genlink + '&access=' + access + '&scalefont=' + scalefont + '&skin=' + skin + '&watermark=' + watermarkmsg +'×tamp=' + timestamp);
totformats++;
if (totformats > maxformats)
window.location.href = '/user?logout=logout';
var docfilename = ((doclang) ? doclang : '') + ((doctype) ? doctype : '');
var pdffilename = docnum + '-' + docfilename + '.pdf';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
// Do IE9 stuff or iPhone/iPad
if (version == 9) {
var ip = this.responseText;
var a = document.createElement("a");
a.style = "cursor: pointer;";
document.body.appendChild(a);
var url = 'http://' + ip + '/IE9/' + loggedInUser + '-' + docnum + '-English.pdf';
a.href = url;
$(a).attr('target','_blank');
a.click();
$(a).remove();
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
else if (isiOS) {
var ip = this.responseText.trim();
ioswindow.location.href = 'http://' + ip + '/IE9/' + loggedInUser + '-' + docnum + '-English.pdf';
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
// Hack to partially fix Chrome error, file is now in Chrome downloads
else if (Math.max(document.documentElement.clientWidth, window.innerWidth || 0) <= 1024 && window.chrome) {
var blob = new Blob([this.response], {type: 'application/pdf'});
var a = document.createElement("a");
a.style = "display: none";
document.body.appendChild(a);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = pdffilename;
a.click();
window.URL.revokeObjectURL(url);
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
else {
saveAs(this.response, pdffilename);
$(doc).removeClass('loader');
$(doc).prop('disabled',false);
}
}
}
xhr.open('GET', 'customer-formatter.xq?masterlang=' + masterlang + '&doclang=' + doclang + '&specialty='+ specialty + '&article=' + docnum + '&user_name=' + loggedInUser + '&territory=' + territory + '&expiry=' + expiry + '&page_width=' + page_width + '&page_height=' + page_height + '&column_count=' + column_count + '&phrasechange=' + phrasechange + '&genlink=' + genlink + '&access=' + access + '&scalefont=' + scalefont + '&skin=' + skin + '&watermark=' + watermarkmsg +'×tamp=' + timestamp);
xhr.setRequestHeader('Authorization','Basic ' + sessinfo);
if (isiOS)
xhr.responseType = 'text';
else
xhr.responseType = 'blob';
xhr.send();
logEvent(docnum, doclang, 'format', specialty, source, docname);发布于 2018-12-23 03:29:42
您的download:download函数的编写方式使它可以使用eXist-db模板。我建议将实际的下载逻辑抽象为单独库模块中的一个单独的函数。
然后,您可以让您的download:download函数调用您抽象的下载逻辑函数,您还可以创建一个新的主模块(如direct-download.xq或其他什么),它只处理URL,然后调用抽象的下载逻辑函数。
https://stackoverflow.com/questions/53870914
复制相似问题