首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >eXist-db REST获取动态pdf请求-无法读取源文件

eXist-db REST获取动态pdf请求-无法读取源文件
EN

Stack Overflow用户
提问于 2018-12-20 14:47:34
回答 2查看 242关注 0票数 0

(eXist 4.4,XQuery 3.1)

我向用户提供下载PDF文档的能力,这些文档在请求时动态创建。请求有两个参数:文档名称(即doc=MS609-0002.pdf)和文档语言版本(即lang=EN)。

输出在download.xql中的函数

代码语言:javascript
复制
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结构如下:

代码语言:javascript
复制
 http://localhost:8081/exist/rest/db/deheresi/download.xql?doc=MS609-0002.pdf&lang=EN

但当我提出这个要求时,我会得到:

代码语言:javascript
复制
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的这种变化

返回具有空白树的下列消息:

代码语言:javascript
复制
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的这种变化

返回:

代码语言:javascript
复制
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请求的全部功能:

代码语言:javascript
复制
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请求的任何配置/权限问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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页面中):

代码语言:javascript
复制
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。

后面的代码是这样的(我剪掉了所有其他东西,只留下了格式化部分):

代码语言:javascript
复制
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,并使用以下方法保存响应:

代码语言:javascript
复制
saveAs(this.response, pdffilename);

这是对FileSaver.js的调用,它处理从XHR保存二进制数据并为您下载二进制数据。我从一个更大的代码中删掉了这一点,它处理了所有的下载,包括从RenderX动态生成的下载,就像您的代码一样,但也包括静态PDF。

这个调用很简单,只是一个到达customer-formatter.xq (在我的例子中,这与调用http://localhost/customer-formatter.xq是一样的)(因为我去掉了/exist,我在Jetty的文章是80):

代码语言:javascript
复制
 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 +'&timestamp=' + 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 +'&timestamp=' + timestamp);
        xhr.setRequestHeader('Authorization','Basic ' + sessinfo);
        if (isiOS) 
            xhr.responseType = 'text';
        else
            xhr.responseType = 'blob';
        xhr.send();
        logEvent(docnum, doclang, 'format', specialty, source, docname);
票数 1
EN

Stack Overflow用户

发布于 2018-12-23 03:29:42

您的download:download函数的编写方式使它可以使用eXist-db模板。我建议将实际的下载逻辑抽象为单独库模块中的一个单独的函数。

然后,您可以让您的download:download函数调用您抽象的下载逻辑函数,您还可以创建一个新的主模块(如direct-download.xq或其他什么),它只处理URL,然后调用抽象的下载逻辑函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53870914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档