首页 新闻 会员 周边 捐助

ASP.NET urlRewrite 重写的URL切换问题,能否自动根据重写规则反射输出URL

0
悬赏园豆:100 [已解决问题] 解决于 2010-12-24 04:58

url重写,一般都是先配置重写规则如:

virtualUrl="^~/(\d+).html"
toUrl = "~/Default.aspx?ID=$1" 

这样就能通过访问/100.html重写到实际的default.aspx?id=100的地址。

然后在页面中这样写: <a href="/100.html"> 而不是原先的<a href="default.aspx?id=100">

假如要修改重写的地址,责要修改所有页面的重写链接,以及重写规则。很是麻烦!

--------------问题来了:
上面输出url的两个a瞄,一个是重写的,一个是未重写的实际地址。 如何自动切换,最笨的方法可能用if(重写==true)就输出/100.html,否则是默认的,在每一个a超连接上进行判断输出,这样很累。
  
能否通过一个方法自动反射出想要的链接呢, 如<a href="<%=getUrl("default.aspx?id=100") %>"> ,这个getUrl(string)的方法去读取规则,反射出virtualUrl地址,这样以后只需要修改重写规则,页面就会自动输出新的规则地址,无需再修改每个页面的超链接。还可以通过判断切换输出,如没开启重写,直接原样返回输出。

想要这个getUrl(string)的方法代码,不要非常详细,大致能实现即可。谢谢


因为getUrl传入的是实际url地址,而在规则里面toUrl的数据不是正则格式,只是匹配格式。这个可能有点难度,还得有点性能。 再谢!

// 我大概的写写,里面关键的集合匹配以及构造虚拟url的代码不知道怎样写了
// 希望高手帮忙. 或提供下其他的思路
public static getUrl(string originalUrl)
{
if(systemIsUrlRewrite)
{
foreach(reurl in reurls)//遍历重写的正则集合
{
if(originalUrl 匹配 reurl.toUrl)
{
return build_virtualUrl(reurl,originalUrl);
//如果集合中有此url的重写规则,就输出此源url的虚拟url,也得用正则吧?

}
}
}
else
{
return originalUrl;//系统没开启url重写,直接返回原始url
}


}

 

明天.NET 老大, 谢谢你的代码思路,我改写了下, 脑子还有点乱, 现在是完全可以反置那些"正规"的规则了,也就是虚拟url和实际url匹配组要相等. 遇到不相等的恐怕还得加一个循环去折腾. 我觉得在反转替换的时候可以直接在正则遍历时进行,正好减少一个循环. 我再清理下头绪,添加个循环处理"不规则"的规则,应该还是3个循环.

这是我改后的:  恳请斧正

再次修改====改为3个循环, 简单测试支持复杂的规则匹配,不限定规则组次序.   想了想或许只有2个循环也能解决  用到使用只需要解决字符转义了.

 

protected void Page_Load(object sender, EventArgs e)
{

UrlRewriteRoute test
= new UrlRewriteRoute();
//test.VirtualPath = @"~/ 数字(\d+) / 字符(\w+) / 字母([a-zA-Z]*) - 无厘头(.*) \.html";
//test.ToUrl = @"~/1.aspx? 字母=$3 字符=$2 无厘头=$4 数字=$1";

test.VirtualPath
= @"~/([a-zA-Z]*)\/(.[0-9]*[a-zA-Z]*)/([0-9]*)/(\w+)/([a-zA-Z]*)\.aspx";
test.ToUrl
= @"~/WebPage/$1/$2.aspx?classid=$2;page=$3;keys=$4";

var result
= ReverseRoute(test);

Response.Write(test.VirtualPath
+ "<br/>" + test.ToUrl + "<br/><br/>");
Response.Write(result.VirtualPath
+ "<br/>" + result.ToUrl + "<br/>");

}

public static UrlRewriteRoute ReverseRoute(UrlRewriteRoute route)
{

UrlRewriteRoute result
= new UrlRewriteRoute();

string New_toUrl = route.VirtualPath; //反转定义
string New_virtualUrl = route.ToUrl;

List
<string> virtualList = new List<string>();

MatchCollection virtualMatch
= Regex.Matches(route.VirtualPath, @"(\(.+?\))");

//先遍历出来转存到List ,List输出内容后倒置成位置索引
foreach (Match m in virtualMatch)
{
virtualList.Add(m.Groups[
1].Value);
}

Regex tourlReg
= new Regex(@"\$(\d+)");

int i = 1;
foreach (Match m in tourlReg.Matches(route.ToUrl))
{
int GroupNum = Convert.ToInt32(m.Groups[1].Value);
if (virtualList.Count >= GroupNum)
{
New_virtualUrl
= New_virtualUrl.Replace(m.Value, string.Format("{0}", virtualList[GroupNum - 1]));
virtualList[GroupNum
- 1] = "$"+i.ToString(); //将虚拟Url的索引位置倒置进去 也就是当前索引
i++;
}

}
int k = 0;
foreach (Match matGroup in virtualMatch)
{
//这里的遍历和预存virtualList是一样的,为了能够对应索引位置
//替换相同索引位置的规则匹配组为新的虚拟匹配组位置索引,已经基本支持更复杂的规则匹配
New_toUrl = New_toUrl.Replace(matGroup.Value, virtualList[k]);
k
++;
}
result.ToUrl
= New_toUrl;
result.VirtualPath
= New_virtualUrl; //这里还要解决字符转义问题
return result;
}

public class UrlRewriteRoute
{
public string VirtualPath { get; set; }
public string ToUrl { get; set; }
}

 

 

 

Richwong的主页 Richwong | 初学一级 | 园豆:120
提问于:2010-12-20 19:26
< >
分享
最佳答案
0

建议可以采用Mvc那种RouteTable模式。

如:<% this.MakeUrl(new {RewriteName="default",Id=100})%> (MakeUrl自己实现对page的扩展)

当然这个UrlWrite你需要重新一下了,需要RewriteName标记区分不同的路由,通过读取配置路由生成实际路径,是否采用重写也简单啦。

 

------------------------

代码很简单,做一点语法分析,不知道对不对:)

附加代码:

public static void Main()
{
UrlRewriteRoute route
= new UrlRewriteRoute() { VirtualPath=@"^~/(\w+)/(\d+)/(\d+)",ToUrl=@"~/default.aspx?domain=$1&id=$2&page=$3"};
var result
= ReverseRoute(route);
Console.WriteLine(result.VirtualPath
+ Environment.NewLine + result.ToUrl + Environment.NewLine);
Console.ReadLine();
}

public static UrlRewriteRoute ReverseRoute(UrlRewriteRoute route)
{
UrlRewriteRoute result
= new UrlRewriteRoute();
List
<List<char>> regs = new List<List<char>>();
bool flag=false;
List
<char> reg=new List<char>();
foreach (char c in route.VirtualPath)
{
if (c == '(')
{
flag
= true;
reg
=new List<char>();
continue;
}
if (c == ')')
{
flag
= false;
regs.Add(reg);
continue;
}
if (flag)
{
reg.Add(c);
}
}
//得到正则
string[] regstrs = regs.Select(p => new String(p.ToArray())).ToArray();


string virtualPath = route.ToUrl;
Regex replaceReg
= new Regex(@"\$(\d+)");
List
<string> matchList = new List<string>();
foreach (Match m in replaceReg.Matches(route.ToUrl))
{
matchList.Add(m.Value);
}
string[] matchstrs=matchList.ToArray();

//VirtualPath -> ToUrl
foreach (string s in matchstrs)
{
int i=Convert.ToInt32(s.TrimStart('$'));
if (regstrs.Length >= i)
{
virtualPath
= virtualPath.Replace("$" + i.ToString(),string.Format("({0})", regstrs[i - 1]));
}
}
//ToUrl->VirtualPath 这个简单只需要按顺序$1,$2```
List<char> to = new List<char>();
int index=0;
foreach (char c in route.VirtualPath)
{
if (c == '(')
{
flag
= true;
continue;
}
if (c == ')')
{
flag
= false;
index
++;
to.AddRange(
"$" + index.ToString());
continue;
}
if (!flag)
{
to.Add(c);
}
}
result.ToUrl
= new String(to.ToArray());
result.VirtualPath
= virtualPath;

return result;
}

public class UrlRewriteRoute
{
public string VirtualPath { get; set; }

public string ToUrl { get; set; }
}

 

收获园豆:100
LittlePeng | 老鸟四级 |园豆:3445 | 2010-12-20 20:08
看了下Mvc的这个RouteTable, 规则都添加到路由里面,根据比较麻烦.
Richwong | 园豆:120 (初学一级) | 2010-12-20 20:34
嘿嘿,可以直接使用现成的System.Web.Routing 做重写,适当封装下也会挺好用的哈。 之前没注意你的那种实现方式很好,好像你用的微软那个UrlReWrite好像是开源的把,可以改写具体实现,不过直接使用的时候通过toUrl确实难以配匹VirtualUrl。不过通过加载的规则的同时自动通过virtualUrl="^~/(\d+).html" ,toUrl = "~/Default.aspx?ID=$1" -》生成vtoUrl = "~/Default.aspx?ID=(\d+)"这个正则就好了。UrlRewrite修改:1.添加配置开关,2.添加外部对规则引用
LittlePeng | 园豆:3445 (老鸟四级) | 2010-12-20 23:32
遍历规则的toUrl, 将匹配符"$1" "$2"之类的符号Replace为匹配组为"(\d+)"之类的,然后就好办了. 就是将匹配符改成匹配组比较麻烦,没思路,主要是匹配的规则不仅仅只有(\d+)数字以及单个匹配.
Richwong | 园豆:120 (初学一级) | 2010-12-21 13:57
呃,有什么麻烦?我想将virtualUrl和toUrl 配匹符反置之后参考UrlWrite的重写路径方法一样吧?至于效率如果结果不理想,适当缓存应该也挺好
LittlePeng | 园豆:3445 (老鸟四级) | 2010-12-21 19:34
哈,你意思是virtualUrl和toUrl里面的规则再复杂也可以反置吗? 我就是不知道具体如何反置,能反置过来好办了,就好直接匹配替换出virtualUrl来. 正规则和反置后的规则都可以缓存起来. 能说说如何反置规则吗?
Richwong | 园豆:120 (初学一级) | 2010-12-21 19:57
嗷,你还非得要我写一个出来······,我就写吧,这里不好写,就附加在回复里面吧
LittlePeng | 园豆:3445 (老鸟四级) | 2010-12-22 21:41
万分感谢, 很好很强大,似乎还点不足,面对复杂的重写规则,反置会出错,不知道能不能修正, 还有个问题是使用toUrl反置成正则规则后的字符转义处理. :: UrlRewriteRoute route = new UrlRewriteRoute() { VirtualPath = @"~/([a-zA-Z]*)\/(.[0-9]*[a-zA-Z]*)/([0-9]*)/([0-9]*)/([a-zA-Z]*)\.aspx", ToUrl = @"~/WebPage/$1/$2.aspx?classid=$2;page=$3;keys=$4" }; 这个规则,其中第5个匹配组是不替换的,这个属于稍微复杂些的规则了, 用你的ReverseRoute后会反置出~/WebPage/([a-zA-Z]*)/(.[0-9]*[a-zA-Z]*).aspx?classid=(.[0-9]*[a-zA-Z]*);page=([0-9]*);keys=([0-9]*) ==>~/$1\/$2/$3/$4/$5\.aspx $5就会再次匹配成数字,原本是26字母的.这个要加判断估计比较复杂. 字符转义倒是可以查找需要转义的字符前面未转义,再加上转义符. 再谢谢了
Richwong | 园豆:120 (初学一级) | 2010-12-24 01:30
明天. 我改了下,敬请斧正, 评论里不能贴,我贴到问题里面了. 奇怪,代码为什么不会缩进...
Richwong | 园豆:120 (初学一级) | 2010-12-24 03:16
已经解决转义 string New_virtualUrl = Regex.Escape(route.ToUrl); 替换的时候还要加上New_virtualUrl = New_virtualUrl.Replace("\\"+m.Value, ,因为$符号也被转义了. 笨笨这样弄好,就基本没啥问题了. 谢谢
Richwong | 园豆:120 (初学一级) | 2010-12-24 04:58
嘿嘿,还是哥们你写得方法好些,相互交流挺好。发现我得好好学下算法才行:)
LittlePeng | 园豆:3445 (老鸟四级) | 2010-12-24 11:26
嗯嗯,应该多多交流。 有很多东西一个人的思绪就是会卡在那里,几个人交流交流就解了。哈哈
Richwong | 园豆:120 (初学一级) | 2010-12-24 13:42
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册