引入:
关于UrlRewriteFilter大家也许都不陌生,尤其那些做过SEO(搜索引擎优化)的同学们都知道,它会吧一个url重写为另外一URL,为什么要这么做呢?因为搜索引擎看待动态的URL非常不舒服(所谓动态URL就是?关联queryParameter,&关联参数对这种url,比如http://1.2.3.4:3333/badurltest?a=1&b=2&c=3这种url.而我们重写后会把它改为静态url,比如http://1.2.3.4:3333/badurltest_1_2_3.html,这种情况下搜索引擎看的比较舒服。
那么我们看下Liferay中如何做到url重写的,当然了,肯定还是按照惯例一样,它会用filter来完成这个工作。
调试分析:
熟悉urlrewrite的人都知道,它一般会采用一个urlrewrite.xml来完成重写的规则配置,我们liferay也不例外。它在$LIFERAY_TOMCAT_HOME/webapps/ROOT/WEB-INF目录下:
我们选取一个最简单的,比如http://172.29.175.236:8080/tunnel-web ,看它是否能重写为http://172.29.175.236:8080/api
很显然,这个URLRewriteFilter是被InvokerFilterChain调用的。我们进入doFilter()方法:因为我们的拿到的sourcecode中的URLRewriteFilter.java无法和jar包中的UrlRewriterFilter.class相匹配,所以我们只能用jd-gui反编译来对照着看。
跳去不重要的行,我们目光停在了第726到728行。
首先,第726行会去利用processRequest(HttpServletRequest,HttpServletResponse)来获取重写url.我们看它的实现,首先它会在第68行把它trim()下去掉首尾空白字符:
trim()完之后,这个url还是/tunnel-web:
然后,在84行将其用utf-8形式将其decode,因为我们都知道最早我们输入的url都被URLEncode过了。
decode完之后,这个originalUrl仍然是/tunnel-web:
然后第95到98行会从请求url中吧contextPath部分移除。
因为如下图所示,我们的contextPath为"",所以98行执行完之后originalUrl依然是/tunnel-web:
从102-107行会吧queryString加载originalUrl的后面:
因为我们没有查询字符串,所以不加任何东西。
然后第123行会获取所有的url重写规则并且保存在变量rules中,它会从urlrewrite.xml中获取所有规则配置信息:
因为最上面,我们在urlrewrite.xml中配置了6条规则,所以从调试信息看,这里rules数组变量有6个元素。
然后从131-141行就会依次遍历这些规则集然后调用规则来重写请求url了,需要注意的是,它是顺序的执行匹配然后重写的,也就是下一个规则会用上一个规则的输出作为输入:
而重写的过程在第135行 execute方法中:
重点:execute()方法的细节:
我们来看下我们的例子,因为我们定义了以下规则:
所以,当请求url是 /tunnel-web时候,当执行到上述第134行时候,它先从urlrewrite.xml中获得了当前规则(匹配上述定义):
然后第135行会调用rule.execute()方法来具体的执行重写:
它先在第74行通过executeBase()方法获取一个RuleExecutionOutput对象,具体不展开了,就是创建一个Matcher对象,如果匹配,就把<from>中的()中的匹配正则表达式的重写内容按照顺序1,2,3等替换为<to>中的重写参数$1,$2,$3等。最终通过调试信息我们可以看出,它计算出了最终的匹配目标:
这里看出,它的replaceUrl 包含了要匹配到的目标,而ruleMatched为true表明通过检验,这个url重写规则匹配当前的url.
而execute()方法最终会调用rewriteRequest()方法来具体的进行重写:
从这里可以看出,因为我们的to type字符串设置为"permanent-redirect",所以我们根据以下规则:
我们的toType被设为2.
所以会执行rewriteRequest的第99-103行,最终会吧rewrittenRequest的permanentRedirect设置为true.
然后到回到UrlRewriter的processRequest()方法中,因为我们已经从execute()方法中返回RewrittenUrl,它的target是/api:
所以第139行会取出这个target,并且作为最后finalToUrl.
总结:
虽然这片调试没有什么技术难度,不过我们还是可以总结出一些有价值的结论:
(1)Liferay的Url重写是通过UrlRewriteFilter来完成的,并且这个UrlRewriteFilter会被InvokerFilterChain所调用。
(2)重写规则会定义在$LIFERAY_TOMCAT_HOME/webapps/ROOT/WEB-INF/urlrewrite.xml文件中。
(3)执行重写的过程如下:首先它会去吧请求url trim()下,再将其utf-8解码成原始url,然后会去除contextPath部分并且后面加上查询字符串部分,得到重写前的输入url。然后,它会吧urlrewrite.xml中的所有重写规则都读取并且存放在Rule数组中,遍历数组对于重写前url一条一条应用程序规则,并且这是递归的,就是一条规则的输出就是下一条规则的输入。直到吧所有的规则全部应用完,才得到最终重写后的输出url.
(4)在应用重写规则时候,它又分为2部分,首先它会在基类(RuleBase)中应用一般规则替换,就是把所有<from>中的用括号括出来的正则表达式匹配的请求内容转为<to>中重写参数指定的模式。其次,它会去读取<to>中的type属性,并且根据type属性的取值来决定对于重写后的url 进行如何后处理。
(5)type属性有6种,分别是redirect,permanent-redirect,temporary-redirect,pre-include,post-include,forward,我们可以根据不同需要为其进行定制。