在应用URLRewrite功能后自动输出重写过的URL

前两天看了老赵的重提URL Rewrite(4):不同级别URL Rewrite的一些细节与特点,并且有人留言问怎样自动输出重写后的URL。我看到之后非常有想法,事实上在我以前研究URL重写的时候也想过这个问题,如果有这种方法的话,将会给我们开发带来大大的方便。正好不久前我刚整理了一下HTML页面生成的方法,里面的Response.Filter给了我很大的灵感。好的,说干就干,花了昨天半天时间,捣鼓出来一个简单的例子,所以也就有了本文。

一、思考

我们在项目中使用URL重写技术,来达到对搜索引擎的友好、人性化URL、清晰的组织架构、新老系统整合等等效果,但同时也给我们的开发带来了一些不便之处。比如VS就会提醒您这个URL并不存在,也给我们的调试工作加大了难度。如果是老系统升级使用URL重写功能的话,那整个URL替换一下也是个不小的工程。如果我们能在HTML产生之后输出之前做些小动作的话,也许能够满足我们的需求。

二、准备

  • 生成好的HTML。这点简单,使用Response.Filter就可以了。如果对Response.Filter还不了解到话,请看这,本文就不多说了。
  • 替换。这点也不难,但需要考虑的是怎么样达到最优化,还请大家来讨论,下面就来说说我的实现。

三、实现

  • URL替换规则

要使用URL重写,那我们在Config里肯定对重写规则有所定义。简单的方法就是定义四条,两条对应URL重写,两条对应URL替换,但好像比较烦哦,正是我们程序员不屑做的事。而且我们这里的URL替换规则正好是前面的这个重写规则的反向,那就用程序来实现吧。我的实现代码:

//Get URL rewrite configs
UrlsCollection rules = UrlsConfig.GetConfig().Urls;

string[] virtualUrl = new string[rules.Count];
string[] destinationUrl = new string[rules.Count];

for (int j = 0; j < rules.Count; j++)
{
    //Remove ~/
    string lookFor = rules[j].VirtualUrl.Substring(2);
    string sendTo = rules[j].DestinationUrl.Substring(2);

    //Replace ? with \\? for Regex
    //Replace &amp; which is used in XML files
    sendTo = sendTo.Replace("?", "\\?").Replace("&amp;", "&");

    string[] array_lookFor = lookFor.Split(new string[] { "(.*)" }, StringSplitOptions.None);
    string[] array_sendTo = sendTo.Split('$');

    //Prepare new lookFor and sendTo
    for (int i = 0; i < array_lookFor.Length - 1; i++)
    {
        string initial;
        if (array_sendTo[i + 1].Length == 1)
        {
            initial = array_sendTo[i + 1];
            array_sendTo[i + 1] = "";
        }
        else
        {
            initial = array_sendTo[i + 1].Remove(1);
            array_sendTo[i + 1] = array_sendTo[i + 1].Substring(1, array_sendTo[i + 1].Length - 1);
        }
        array_lookFor[i + 1] = initial + array_lookFor[i + 1];
    }

    //Join with new Regex characters
    virtualUrl[j] = "^" + string.Join("(.*)", array_sendTo) + "$";
    destinationUrl[j] = string.Join("$", array_lookFor);
}

我做了张图,时间紧,比较丑,但足以说明事情了。

做了如上图的替换之后,在用新的分隔符链接起来,就变成了我们所需要的正则表达式了。

  • 开始替换

有了正则表达式,替换就简单了。我的实现代码:

string[] body = Encoding.UTF8.GetString(data).Split(new string[] { "href=" }, StringSplitOptions.RemoveEmptyEntries);

for (int i = 0; i < body.Length; i++)
{
    string s = body[i];

    for (int j = 0; j < virtualUrl.Length; j++)
    {
        Regex re = new Regex(virtualUrl[j], RegexOptions.IgnoreCase);
        //<a href=".....">
        if (s.StartsWith("\""))
        {
            string href = s.Substring(1, s.Substring(1).IndexOf('"'));
            if (re.IsMatch(href))
            {
                string newhref = re.Replace(href, destinationUrl[j]);
                body[i] = "\"" + path + newhref + s.Substring(s.Substring(1).IndexOf('"') + 1);
            }
        }
        //<a href='.....'>
        else if (s.StartsWith("'"))
        {
            string href = s.Substring(1, s.Substring(1).IndexOf('\''));
            if (re.IsMatch(href))
            {
                string newhref = re.Replace(href, destinationUrl[j]);
                body[i] = "'" + path + newhref + s.Substring(s.Substring(1).IndexOf('\'') + 1);
            }
        }
        //<a href=.....>
        else
        {
            //The operation is not implemented.
        }
    }
}

首先用"href="来分割一下,然后再来判断URL是由 "" 或 '' 或“什么都没有”来包住URL的,其中第三个比较麻烦,我也就没有具体来实现它。同时我也没有做Trim、去掉换行等操作。

  • 输出

替换完了HTML,我们再用"href="组合起来,就可以输出了。

//Get formative HTML
byte[] outdata = Encoding.UTF8.GetBytes(string.Join("href=", body));
//Render to browser
m_sink.Write(outdata, 0, outdata.GetLength(0));

四、小结

至此,我们这个简单的URL自动重写功能就实现了,当然,其中还有很多需要完善和考虑到地方,比如如何处理Javascript中的location.href等等。由于本例纯属“自动重写URL”这种方法的可行性研究,所以使用的都是假设的场景,并没有在实践项目中应用,在此仅作块砖头,有玉的尽管来砸吧。

PS:由于下午要回家过年,所以写的比较匆忙,还请大家见谅。本人第一次发首页帖,因为没有看到过类似的文章,所以就发在了首页上,其实没什么技术性,如有觉得不妥,我立马撤下:)。

posted on 2008-02-05 11:02  Superstone  阅读(2381)  评论(5编辑  收藏  举报

导航