好有成就感的一个晚上啊,虽然困了,也要把晚上的收货整理出来,必须的!
以前粗略的看过一些关于URL重写的文章,大致分为在IIS下、ASP.NET下实现的。还有说在IIS6下不容易实现用ASP.NET重写URL,在IIS7下很容易用ASP.NET实现的。今天通过试验,终于弄清楚其中的奥秘了。
首先在IIS6下不容易截获请求而在IIS7下容易截获请求的说法是错误的,在IIS6下只需要在IIS6的网站属性->主目录->应用程序配置->设置中插入一个“通配符应用程序映射”(C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/aspnet_isapi.dll)。插入这个的作用实际就是:不管是什么类型的文件,比如.html、.asp、.jpg等等,甚至是以/结尾的目录,都发到aspnet_isapi.dll,要由aspnet_isapi.dll来“过目”,如果不做这个配置,那么像.asp可能旧有asp_iisapi.dll来处理了。
这里要确保“确定文件是否存在”处于未选中状态,这样IIS才不会实际去检查文件是否存在,因为重写的URL指向的文件物理上是不存在的。
做了上述配置之后,不管是什么样的URL,都会进入到ASP.NET的处理程序,可以随意重写。
另一个需要注意的问题是,网上有几个不同版本的URL重写方法,给的类也是不同的,配置 web.config的方法也是不同的,所以,千万要弄清,web.config 中的配置很多,不要张冠李戴。
web.config 中需要配置的几个地方列出如下:
- <configSections>
- <section name= "RewriterConfig" type= "URLRewriter.Config.RewriterConfigSerializerSectionHandler, URLRewriter" />
- </configSections>
- <appSettings />
- <connectionStrings>
- <httpModules>
- <add type= "URLRewriter.ModuleRewriter, URLRewriter" name= "ModuleRewriter" />
- </httpModules>
- <!-- 这里网上的资料都是说:可以配置为http处理模块,也可以配置为处理程序,好像两个只要用一个就可以了,我这里用的是处理模块 -->
- <RewriterConfig>
- <Rules>
- <RewriterRule>
- <LookFor>(.+)/(.+).html</LookFor>
- <SendTo>~/$2.aspx</SendTo>
- </RewriterRule>
- <RewriterRule>
- <LookFor>~/(/d{4})/(/d{2})/(/d{2})/.aspx</LookFor>
- <SendTo>~/ShowBlogContent.aspx?year=$1&month=$2&day=$3</SendTo>
- </RewriterRule>
- </Rules>
- </RewriterConfig>
最后这部份就是控制重写的,只需要用正则表达式匹配请求url,然后给出新的url就可以,这里可以使用正则表达式中的后向引用。
还有一个问题,就是处理回发。
比如访问一个被重写了的url,而这个url上面有一个窗体,虽然打开窗体的时候,使用的是重写前的url,但是当点击窗体的提交按钮的时候,窗体会被定向到重写后的实际的url去。解决这个问题的办法网上也提供了,而且还有vb版本,和C#版本的。
具体的实现方法就是“利用ASP.NET 2.0控件适配器 扩展架构来定制控件的输出”,说白了就是ASP.NET 2.0提供了一个功能,可以手工的改写服务器控件。那么我们可以改写form控件的窗体的action,也就是提交路径的属性,下面给出C#版本,VB版本可以网上搜到。
需要两个文件,分别是:
App_Browsers/Form.browser
- <browsers>
- <browser refID= "Default" >
- <controlAdapters>
- <adapter controlType= "System.Web.UI.HtmlControls.HtmlForm"
- adapterType= "FormRewriterControlAdapter" />
- </controlAdapters>
- </browser>
- </browsers>
App_Code/FormRewriter.cs
- using System.Data;
- using System.Configuration;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.WebControls.WebParts;
- using System.Web.UI.HtmlControls;
- /// <summary>
- /// FormRewriter 的摘要说明
- /// </summary>
- public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
- {
- public FormRewriterControlAdapter()
- {
- }
- protected override void Render(HtmlTextWriter writer)
- {
- base .Render( new RewriteFormHtmlTextWriter(writer));
- }
- }
- public class RewriteFormHtmlTextWriter : HtmlTextWriter
- {
- public RewriteFormHtmlTextWriter(HtmlTextWriter writer)
- : base (writer)
- {
- base .InnerWriter = writer.InnerWriter;
- }
- public RewriteFormHtmlTextWriter(System.IO.TextWriter writer)
- : base (writer)
- {
- base .InnerWriter = writer;
- }
- public override void WriteAttribute( string name, string value, bool fEncode)
- {
- //If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
- //then replace the value to write with the raw URL of the request - which ensures that we'll
- //preserve the PathInfo value on postback scenarios
- if (name == "action" )
- {
- HttpContext context = HttpContext.Current;
- if (context.Items[ "ActionAlreadyWritten" ] == null )
- {
- //We will use the Request.RawUrl property within ASP.NET to retrieve the origional
- //URL before it was re-written.
- value = context.Request.RawUrl;
- //Indicate that we've already rewritten the <form>'s action attribute to prevent
- //us from rewriting a sub-control under the <form> control
- context.Items[ "ActionAlreadyWritten" ] = true ;
- }
- }
- base .WriteAttribute(name, value, fEncode);
- }
- }
经过这么一番折腾后,URL重写就可以在 Windows Server 2003 + IIS6 + ASP.NET 2.0 下实现了。
不过,事情没那么简单,改写是实现了,那么页面上那么多连接的地址都要手工去修改吗?手工修改后在vs.net 的 ide 里面会不会出问题?
留作以后解答……
微软的URL重写类在这里下载,下载后只需编译里面的URLRewriter类为DLL文件,然后在你的项目中做个引用就可以了。
http://www.microsoft.com/china/msdn/library/webservices/asp.net/URLRewriting.mspx