现在在.net中,我们有很多方法可以实现路径的重写,不论是外部插件还是代码控制,总归是为了让URL对外更加的短小,易懂并且不包含敏感信息.
所以,在这里,我主要介绍如何利用PageHandlerFactory类来拦截URL请求并且进行重写的.
这里类是所有的aspx页面请求的默认父类对象,页面的任何请求都可以被其捕获,我们可以通过重写其中的getHandler方法来实现自我控制.
功能需求
不过,在开始写之前,我们先看看我们需要用到什么功能.
- URL重写需要支持GET, POST请求方式.
- URL重写需要支持实时的DEBUG功能,也就是能够跳转到重新定向的页面进行调试.
代码构建
基于这两点(其实这两点在开发过程中也是很重要的两点),我们构建如下的代码页:
using System.Web; using System.Web.UI; using System.Web.SessionState; using System; namespace AsyncFactoryWEB { public class RewriterFactory : PageHandlerFactory,IReadOnlySessionState { private bool flag = true; public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path) { string[] urlSegments = context.Request.Url.Segments; //获取URL片段 int urlLen = urlSegments.Length; //获取URL的片段长度 if (urlLen <= 1) //当前请求为根目录页面,则不进行处理 flag = false; else //当前请求不是根目录页面,进行处理 flag = true; if (flag) { string conceratePath = ((char)RewriteSettings.splitter.slash).ToString(); string slashChar = ((char)RewriteSettings.splitter.slash).ToString(); // /斜线 string equalChar = ((char)RewriteSettings.splitter.equal).ToString(); // =等号 string andChar = ((char)RewriteSettings.splitter.and ).ToString(); // &符号 string extension = ((char)RewriteSettings.splitter.dot ).ToString().Combine(RewriteSettings.fileExtension.aspx.ToString()); // .aspx后缀 string concerateParams=string.Empty; for (int i = 0; i < urlLen; i++) { string curSegment = urlSegments[i]; if (curSegment.LastIndexOf(slashChar) >= 0) //如果检测片段中带有左斜线 curSegment = curSegment.Substring(0, curSegment.Length - 1); //将斜线去掉 if (!string.IsNullOrEmpty(curSegment)) { if (curSegment.Contains(equalChar)) //如果带有等号,则表明应该进行 ***.aspx?id=1 类似的拼接 { if (i == urlLen - 1) concerateParams = concerateParams.Combine(curSegment); else concerateParams = concerateParams.Combine(curSegment.Combine(andChar)); } else if (!curSegment.EndsWith(extension)) //如果不是以.aspx结尾的 conceratePath = conceratePath.Combine(curSegment.Combine(extension)); else conceratePath = conceratePath.Combine(curSegment); } } string newPath = context.Server.MapPath(conceratePath); //得到物理目录 context.RewritePath(conceratePath, string.Empty, concerateParams); //重写路径,并传入parameters try { IHttpHandler iHandler = PageParser.GetCompiledPageInstance(conceratePath, newPath, context); //重写handler对象 return iHandler; } catch (Exception ex) { throw new Exception(ex.Message); } } else { return base.GetHandler(context, requestType, virtualPath, path); } } } }
代码注释比较清楚,就是先获取URL路径,然后进行处理拼接,最后返回一个Handler对象即可.
下面来测试以下, 在Default.aspx中,我们前台代码如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AsyncFactoryWEB._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Url Rewrite testing daemon</title> </head> <body> <div>Using Get method to <a href="WebForm1/type=0/partype=1/testUserName=myRobot/">redirect</a> another page.</div><br /> <hr style="height:1px;" /> <form id="form1" action="WebForm1/t=1/" method="post"> <div>Using Post method to redirect another page.</div> <div> UserName:<input type="text" name="UserName" style="border:none;border-bottom:1px solid black;"/><br /> UserPhone:<input type="text" name="UserPhone" style="border:none;border-bottom:1px solid black;"/><br /> <input type="submit" value="Send" /><br /> </div> </form> <hr style="height:1px;" /> </body> </html>
可以看出其中有两种测试方式:
Get方式:
<a href="WebForm1/type=0/partype=1/testUserName=myRobot/">redirect</a>
Post方式:
<form id="form1" action="WebForm1/t=1/" method="post">
跳转页面为WebForm1.aspx,后台代码为:
using System; using System.Web.UI; using System.Collections.Specialized; namespace AsyncFactoryWEB { public partial class WebForm1 :Page { protected void Page_Load(object sender, EventArgs e) { Response.Write("-----------------Using GET Method---------------------<br/>"); NameValueCollection queryStringCollection = Request.QueryString; foreach (string key in queryStringCollection.Keys) { Response.Write(string.Format("QueryString [{0}] value : {1} ",key,queryStringCollection[key])); Response.Write("<br/>"); } Response.Write("-----------------Using POST Method---------------------<br/>"); NameValueCollection formStringCollection = Request.Form; foreach (string key in formStringCollection.Keys) { Response.Write(string.Format("FormString [{0}] value : {1} ", key, formStringCollection[key])); Response.Write("<br/>"); } } } }
测试结果
当利用Get方式测试时候,我们会跳转到WebForm1.aspx, 显示结果如图:
-----------------Using GET Method--------------------- QueryString [type] value : 0 QueryString [partype] value : 1 QueryString [testUserName] value : myRobot -----------------Using POST Method---------------------
可以看到成功获取了数据.
当利用Post方式测试的时候,我们会跳转到WebForm1.aspx,显示结果如图:
-----------------Using GET Method--------------------- QueryString [t] value : 1 -----------------Using POST Method--------------------- FormString [UserName] value : 程序诗人 FormString [UserPhone] value : 13103993996
数据均能正确捕获.
那么调试功能怎么样呢? 当我们在webForm1.aspx中打上断点的时候,由于PageHandlerFactory会捕获所有请求,所以当返回创建的Hander的时候,会调用processrequest来处理WebForm1.aspx中的方法调用,所以会进入断点.
当然,在上述示例中,我定义的URL实在是太过于难看,你可以自定义自己的URL解析规则.
最后,我们需要在web.config文件<httpHandlers>中加上节点配置.
<add verb="*" path="*" type="AsyncFactoryWEB.RewriterFactory,AsyncFactoryWEB"/>
希望对你有用.
代码下载