代码改变世界

【伪】另类方法实现URL重写

2010-09-10 00:00  Feather  阅读(195)  评论(0)    收藏  举报

关于URL重写的讨论很多,方法也很多,主要也无异于两种,一个是通过配置服务器,一个是通过配置ASP.Net的IHttpModule等底层设置。实现这些功能的组件网上也不少,ASP.Net MVC框架里面也有一个独立于该框架的URL重写组件,里面具体怎么实现,我也不太清楚,毕竟我也只是弱弱地玩了一下而已。

可能很多人看这我这个url就看出来是怎么实现的,如果你就是这些大牛,又或者你觉得我的url不够帅,请跳过。

帅!伪!

嗯,本文的主旨有两个:帅和伪。就是用最伪的方法尽可能地让URL更帅,本着这个原则,我们开始吧。

为了突出我们本方法的效果,增强广告效应,我们先看看我们未经整容前的URL:

文章列表页:www.vinqon.com/home.aspx?catid=3&page=2

 

第一次整容

第一个url奇丑无比,有两个参数,我们先把这两个参数组合一下,改成这样:

第一次整容:www.vinqon.com/home.aspx?catid=3-2

后台接收参数的动作要稍微改一下,可以把catid的值用spilt为数组或者用正则表达式把N个参数分离出来。

现在好了点,就算是有N个参数,也顶多这样子:www.vinqon.com/home.aspx?catid=1-6-12-56

或者用斜杠做分隔符,看起来更加伪:www.vinqon.com/home.aspx?catid=3/6/12/56

 

第二次&第三次整容

看看上面那个,前后斜杠塞了这么多字符,感觉很不爽,我们看得出,这里的catid五个字母没有什么意义,用一个c代替一下看看。

第二次整容:www.vinqon.com/home.aspx?c=3/6/12/56

还是很恶心,那个c不要到底行不行呢?试一下:

www.vinqon.com/home.aspx?3/6/12/56

这下懵了,没有了c,3/16/12/56是不是成了“名值对应”中的名呢?

试一下获取:Request.QueryString["3/16/12/56"],结果取了个null,这下奇怪了,服务器到底怎么理解这堆参数呢?

我又抱着尝试的心理,输出了一下:Request.QueryString.Count,结果竟然为1!这么说服务器还是认为这是一个参数的,我立刻用了另外一个方式获取这个参数::Request.QueryString[0]

这次终于可以把这堆参数取出来了。看来,当我们不用名值对应方式表示参数,而是直接用一段字符串表示,服务器会把它当作一个匿名参数。

现在,让我们看看第三次整容的效果:

第三次整容:www.vinqon.com/home.aspx?3/6/12/56

现在,这个样子的网址让人好接受一点了,但是,既然都做到这个地步了,可不可以再找找办法把那个恶心的文件后缀隐藏一下呢?

 

第四次&第五次整容

有一个很好的办法,在IIS中把home.aspx设置成默认首页,然后,url就可以变成这样了:

第四次整容:www.vinqon.com/?3/6/12/56

但是,这里带来了一个新的问题,每个页面都要这么帅,难道都设置成首页?即使这么设置了,也是行不通的。我这里的解决方案是,做一个跳转页面。现在我们的默认首页还是设置成Default.aspx,我们所要请求的每一个页面都作为一个参数解析。先看看效果:

第五次整容:www.vinqon.com/?home/3/6/12/56

Default页面会用正则获取第一个参数作为页面地址,从而找到跳转页面,为了保存页面这么帅,我们使用 Server.Transfer方法实现跳转,它可以把当前Request数据转移到目的页面,所以不需要大量修改原来页面解析参数的代码。

每一个页面的参数格式可能都不一样,所以我写了一堆Regax数组,一个个尝试匹配,这种方式可能不太好,以后研究参考一下MVC框架的实现方式,重写一下这部分。

private string ParseUrl(string url)
    {
        StringBuilder sb = new StringBuilder();
        Regex[] reg = new Regex[]{
                new Regex(@"(home|lab|books)/(\d*)-(\d*)"),
                new Regex(@"(home|lab|books)/(\d*)()"),
                new Regex(@"(edit|detail)/()()(\d*)"),
                new Regex(@"(home|lab|books|edit|login)")
            };
        for (int i = 0; i < reg.Length; i++)
        {
            Match m = reg[i].Match(url);
            if (m.Success)
            {
                sb.Append(m.Groups[1].Value + ".aspx?");
                if (m.Groups[2].Value != "") { sb.Append("catid=" + m.Groups[2].Value); }
                if (m.Groups[3].Value != "") { sb.Append("&index= " + m.Groups[3].Value); }
                if (m.Groups[4].Value != "") { sb.Append("&id=" + m.Groups[4].Value); }
                return sb.ToString();
            }
        }
        return "home.aspx";
    }

 

总结

其实这种玩意有很多副作用,跟ASP.Net MVC框架一样,不能正常PostBack,这意味了很多服务器控件不能正常使用,而且这个问题可能是不能解决的。其实我个人是比较喜欢直接用HTML标签带提交表单的,感觉比较原生态一点。这些问题后续再说吧。

最后,对比一下吧:

整容前:www.vinqon.com/home.aspx?catid=3&page=2

整容后:www.vinqon.com/?home/3-2