我的eXist-db应用程序中有许多动态页面,到目前为止,这些页面已经通过硬编码输入进行了测试。现在,我必须冒险进入最不适应的域:eXist-db中的URL映射/重写。
这是基本方案。当用户想要在我的网站上查看中世纪文档时,他们可以搜索列表并单击链接,也可以直接输入URL。无论如何,该网址将是:
www.foo.com/doc/MS609-0020
/ doc /表示您正在查看文档,而MS609-0020
实际上是文档的名称(反映了XML文件,即MS609-0020.xml
)。
所有此类文档将通过位于以下位置的通用页面输出:
/db/apps/deheresi/document.html
此document.html
包含一些模板,这些模板需要来自请求的文档名称MS609-0020.xml
才能知道要处理的内容。我已将此全局可用变量命名为$currentdoc
。使用此变量,不同的模板将获得组装document.html
所需的数据。
然后将HTML发送到www.foo.com/doc/MS609-0020
下的浏览器
如果找不到文档名称,则将用户定向到“找不到文档页面”。
如您所见,我的解释是基本的-反映了我仍然使用eXist和XQuery进行培训的事实。
我已经阅读了Siegel / Retter的eXist书中的各章,但是如何在模块中完成重新映射,以及如何与必需的parameters
一起传递...无论我受到多少黑客攻击,对于我来说都不是一件好事通过这个。
对于从伪代码和指令到某些摘要的任何指导,我将深表感谢。一旦我知道如何处理这个请求,然后作为实践我就会将其汇总。
非常感谢。
注意:我要补充一点,这将是一个公共站点,不需要查看文档的权限。
NB 2:一旦符合条件,我将悬赏这个问题。
下面是Siegel / Retter的书中的图表。
答案 0 :(得分:1)
此答案仅涵盖基本的URL重写,并假定eXist应用程序是使用我称之为“基本” eXist应用程序体系结构构建的:
/db/apps/my-app
中。EXIST_HOME/tools/jetty/etc
中的Jetty配置文件,EXIST_HOME/webapp/WEB-INF/web.xml
中的XQuery servlet配置文件或在webapp/WEB-INF/controller-config.xml
处eXist的URL重写的基本配置进行修改。http://localhost:8080/exist/apps/my-app
上访问该应用程序。 (如果目标是通过http://my-server/
之类的URL为该应用程序提供服务,并将其路由到http://localhost:8080/exist/apps/my-app
处的eXist,则最好由反向代理服务器处理,这超出了“基本”范围eXist应用架构。)controller.xql
文件)而非RESTXQ来处理URL重写。 基于这些假设,我们可以创建完全自定义的URL,使我们可以采用以下URL:
http://localhost:8080/exist/apps/my-app/doc.xq?filename=my-document.xml
并通过以下方式提供相同的资源:
http://localhost:8080/exist/apps/my-app/doc/my-document
要完成此操作,我们需要在您应用的根集合中创建一个名为controller.xql
的新XQuery主模块(必须完全称为它,我们将其称为应用的“控制器”)。 :/db/apps/my-app/controller.xql
。这是一个特殊的模块,当请求到达/apps
URL空间中的路径(例如http://localhost:8080/exist/apps/...
)时,eXist首先寻找该模块。通常,一个应用程序只有一个控制器,而eXist支持多个控制器。 eXist会查看目标集合,然后从最深的分支一直到根/db/apps
集合,再向上查看集合树。
控制器的目的是获取有关请求的信息(所请求的路径以及有关应用程序上下文的其他信息),并返回一种特殊的指令,该指令告诉eXist如何路由请求。有关请求的关键信息通过一系列外部变量(您不必为您定义eXist集且您可以引用的变量)向您的查询公开,包括,最重要的是, $exist:path
-请求URL中位于包含控制器的集合路径之后的部分。因此,在上面的URL中,$exist:path
等于/doc/my-document
。
现在,让我们创建一条指令,该指令采用此路径并将请求转发(与filename
参数一起使用到您的实际端点:
xquery version "3.1";
declare variable $exist:path external;
declare variable $exist:resource external;
declare variable $exist:controller external;
declare variable $exist:prefix external;
declare variable $exist:root external;
if (starts-with($exist:path, "/doc/")) then
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<forward url="{$exist:controller}/doc.xq">
<add-parameter name="filename" value="{$exist:resource}.xml"/>
</forward>
</dispatch>
else
<ignore xmlns="http://exist.sourceforge.net/NS/exist"/>
在第一段代码(序言)中,此控制器显式声明eXist提供给控制器的变量。在查询的主要部分,条件表达式处理两种情况:
如果请求的路径以/doc/
开头,那么我们希望通过doc.xq
处理请求-/db/apps/my-app/doc.xq
中应用程序中的XQuery模块。除了键入完整路径之外,我们可以将/db/apps/my-app
替换为$exist:controller
-这是找到活动控制器的集合的数据库路径。我们也知道doc.xq
需要一个filename
参数,因此我们从$exist:resource
变量中显式构造该变量,该变量始终为我们提供最后斜杠后的请求网址部分-例如, my-document
在上面的示例网址中。从控制器将请求转发到的查询的角度(例如doc.xq
),它认为控制器已直接接收到请求,并且可以通过request:get-parameter()
函数访问请求参数。例如,doc.xq
可以仅包含:
xquery version "3.1";
let $doc := request:get-parameter("filename", ())
return
<p>Who's looking for {$filename}?</p>
对上述URL的请求将返回<p>Who's looking for my-document.xml?</p>
。
对于其他任何请求,我们将在不执行任何转发或其他URL操作的情况下让它们通过。
如果您使用的是eXist的HTML模板功能,则可能会将请求转发到模板(document.html
),而不是查询(doc.xq
)。在这种情况下,该指令变得更复杂了 :
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<forward url="{$exist:controller}/document.html"/>
<view>
<forward url="{$exist:controller}/modules/view.xql">
<add-parameter name="filename" value="{$exist:resource}.xml"/>
</forward>
</view>
</dispatch>
在这里,我们将请求转发到document.html
,但是结果通过eXist的模板处理程序模块传递,该模块通常存储在应用程序的modules/view.xql
文件中。 (请注意,<add-parameter>
指令已移至第二个<forward>
指令。)
eXist文档的URL页面上描述了其他外部变量(即$exist:root
和$exist:prefix
)和其他类型的指令(即<redirect>
和其他子元素)重写http://exist-db.org/exist/apps/doc/urlrewrite。尽管该页面当前警告它已过时,但我认为它仍然是一个很好的资源。
eXist的URL重写功能的强项是您可以使用XQuery的完整表达能力来确定应用程序如何路由和接收URL。缺点是,控制器可能会变成一连串的条件条件,难以维护。只要尝试使控制器逻辑尽可能简单即可。学习外部变量也可能需要一些时间。我建议充分利用日志记录(通过util:log
或console:log
函数来输出外部变量的值以及有关请求的其他信息,可以通过request:get-url()
和其他request:get-*
个函数)查看每个请求的处理情况,直到您掌握了它。您可能还会发现,在可用源代码的其他应用程序中调查控制器文件,并在此处提出更多问题会很有帮助!