WebX的url生成及URIBroker的问题和解析

前提条件

将WebX应用部署在“/”上,新建一个component名为“happy”。

其中的happy对应的uri对象配置如下:

<uris:uri id="server" requestAware="true" />
<!-- happy -->

<uris:turbine-uri id="happyModule" exposed="true" extends="server">
<componentPath>/happy</componentPath>
</uris:turbine-uri>
<uris:turbine-content-uri id="happyContent" exposed="true" extends="happyModule" />

诡异的现象

当我们分别打开“http://127.0.0.1:8081/happy/”、“http://127.0.0.1:8081/happy/index”和“http://127.0.0.1:8081/happy/index”时,我们发现:

  • 在“http://127.0.0.1:8081/happy/”中,$happyModule和$happyContent都被解析为“http://127.0.0.1:8081/happy/happy”,显然,这不是我们想要的结果。
  • 在“http://127.0.0.1:8081/happy/index”中, $happyModule和$happyContent都被解析为“http://127.0.0.1:8081/happy/index/happy”,这,跟我们想要的相差更多了
  • 在“http://127.0.0.1:8081/happy/index.htm”中, $happyModule和$happyContent都被解析为“http://127.0.0.1:8081/happy”,后面少了个“/”,嗯,还凑合。

我们先来看一下,为啥上面的若干情况如此诡异呢?考虑以下四个URL:

  • http://127.0.0.1:8081/happy
  • http://127.0.0.1:8081/happy/
  • http://127.0.0.1:8081/happy/index
  • http://127.0.0.1:8081/happy/index.htm

其实,他们指向的component都是happy,对应的screen都是index。而事实上,WebX也是这么映射到对应的screen的——因为我们能够正常访问页面,而且都是happy下index的内容,对吧。理论上,我们要求WebX对确定的映射内容也返回稳定的渲染结果,而事实却并非如此。为什么呢?我们要深入源代码一探究竟。

深入源码

先简单介绍一下,在com.alibaba.citrus.service.uribroker.uri.URIBroker类中,有一个叫path的数组,里面存放了杠与杠之间的各部分。比如/aaa/bbb/ccc/,那么这个数组存放的是[aaa, bbb, ccc]。此类还有一个叫renderPath()的函数,作用是把path中的各个元素组合起来。如上面的数组会组合成“/aaa/bbb/ccc”。看起来不错,不过少了最后的一道杠。

回到上面的例子,为什么会出现了两次“happy”呢?直接原因,是path数组中存了两个“happy”。根本原因,是因为request.getServletPath()返回了“/happy/”,导致ServletURIBroker类中populateWithRequest()函数误以为当前的servlet是happy。因为在j2ee中,后面处理URI时会把servlet部分切割掉,所以多加了一次“happy”。这是不正确的,因为当前的servlet应该是“/”才对!

而这个getServletPath()函数,则是com.alibaba.citrus.service.requestcontext.rewrite.impl.RewriteRequestContextImpl#RequestWrapper中定义的。

论坛已经有人提出相关的问题:http://www.openwebx.org/forum/showthread.php?tid=91&highlight=servletpath。两年过去,仍旧如故。

解决

相当于写死了URL(参见http://openwebx.org/forum/showthread.php?tid=478和http://hi.baidu.com/epplera/item/5877681cce410e221994ec67)。

方法1:

使用turbine-content-uri,并且增加:<contextPath>Web App的部署目录,一般部署在根目录则填“/”</contextPath>

方法2:

<uris:uri id="server" requestAware="false">
<serverName>127.0.0.1</serverName>
<serverPort>8081</serverPort>
</uris:uri>

还凑合的一道杠

为什么说“http://127.0.0.1:8081/happy”还凑合呢?因为,Spring框架中,当我们直接访问“http://127.0.0.1:8081/happy”时,Web服务器发现该网址不存在,于是就返回302跳转到“http://127.0.0.1:8081/happy/”去,所以最后那个是可以正常访问的,虽然跟我们想要的还是差了一道杠(差了网址结尾的“/”)。

不过,一道杠的差别,却不是轻易就能够解决的。话分两头:一方面,想要用turbine-uri在后面加一道简简单单的杠,几乎是不可能的,后文详述原因;另一方面,如果turbine-uri是指向python编写的web app(尤其是用强哥框架,英文名Django框架)的话,就不一定会自动给你补上后面的一道杠,而是冷冰冰地返回一个404错误。

一道杠的距离

这时候,再说一下,WebX中,如果要在uri后面加一道杠,究竟有多难?答案是很难。假设我们分别要生成“http://blog.creke.net/tag/linux/”和“http://blog.creke.net/803.html”,注意后面有道杠。看看下面的配置:

<uris:uri id="crekeServer" requestAware="false" >
<serverName>blog.creke.net</serverName>
</uris:uri>

<uris:turbine-content-uri id="crekeLink1" exposed="true" extends="crekeServer" >
<contentPath>/tag/linux/</contentPath>
</uris:turbine-content-uri>
<uris:turbine-content-uri id="crekeLink2" exposed="true" extends="crekeServer" >
<componentPath>/tag</componentPath>
<contentPath>/linux/</contentPath>
</uris:turbine-content-uri>
<uris:turbine-uri id="crekeLink3" exposed="true" extends="crekeServer" >
<target>/tag/linux/</target>
</uris:turbine-uri>
<uris:turbine-content-uri id="crekeLink4" exposed="true" extends="crekeServer" >
<contentPath>/803.html</contentPath>
</uris:turbine-content-uri>

生成的结果分别是:

  • http://blog.creke.net/tag/linux
  • http://blog.creke.net/tag/linux
  • http://blog.creke.net/tag/linux
  • http://blog.creke.net/803.html

根本原因是,uriBroker将任何URL的路径部分都一视同仁地分解为上文所述的path数组。这对于有后缀名的“http://blog.creke.net/803.html”来说无所谓,反正“803.html”是path的一个元素,直接加就对了;但是对于“http://blog.creke.net/tag/linux/”来说,uriBroker并不会记录是否需要补上最后的一道杠,也就是被吞掉了。

总结

在WebX中,如果不想在配置中写死URL前缀,那么除了首页外,总是要加上index.htm来标示默认页面。而如果要生成最后带“/”的URL的字符串,则不要使用URIBroker类。

最后,还是用WebX文档中的一句话来作总结吧:“我并不是说所有的框架都一样好,而是说只要假以时日,所有的框架在发展过程中,必然会积聚好的方面,淘汰坏的方面,从而变得足够好。从这个角度看,的确没有特别明显的理由来选择Webx,但也没有明显的理由不选择Webx。”(via http://openwebx.org/docs/preface.html#d0e76)

4 comments

  1. Roy says:

    Michael Zhou authored 6 months ago

    git上最后一次提交是6个月以前...我比较看重可持续性

    1. creke says:

      哈哈,说不定他们在忙别的项目

  2. Roy says:

    但是6个月都没有一个patch,的确有点匪夷所思:)

    没用过WebX,看起来配置有点多,不知道支持注解不。不然会很麻烦……

    1. creke says:

      他的官网文档提到了“用XML编程”的哲学。支持部分注解的。

Leave a comment