K_Reverter的网页开发记录

要么不做,要么就当作艺术品来做!

导航

关于URL重写引发的PostBack问题

我是在DotText的评论功能不正常的情况下发现并开始寻求这个问题的解答的,经过多方位的搜求后还是没有解决的办法,最后只好把这个问题提交到了CSDN

以下是CSDN中关于本问题的所有讨论,我就不多说了:

CSDN - 专家门诊 -
主  题:
关于URL重写引发的PostBack问题
作  者: skywatcher (天空守望者)
信 誉 值: 94
所属论坛: .NET技术 ASP.NET
问题点数: 50
回复次数: 31
发表时间: 2005-9-24 17:05:55

我的网页使用了URL重写功能,可是随即我发现网页的PostBack功能失效了,我因为使用虚拟主机,无法更改IIS设置,因此是通过设置错误页面而实现的URL重写,现在问题是:
在页面回发的时候,页面的IsPostBak总是false,虽然调试的时候发现Request之中的数据确实是存在的而且发送到了,可是这些数据并没有被设置到相应的服务器控件之中,所以当然也就没有执行相应的服务器端事件,我找了很久也没有找到一个相关的方法,请问这个问题有什么解决的方法么?
回复人: foxconn_nich() ( ) 信誉:100 2005-9-24 17:11:22 得分:0
 

关注,帮顶
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-24 17:45:26 得分:0
 

“在页面回发的时候”是什么意思呢?Url一旦被修改,浏览器向服务器发送http GET命令,而不是Post页面,这是不可能有回发数据。
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-24 17:49:49 得分:0
 

简单办法是原来页面刷新,同时弹出一个错误页面。
复杂一点的办法是让当前页面的显示区域的 visible=false,然后装载一个错误显示控件(例如 error.ascx)来显示,这时候“回到上一页”其实就是 visible=true。
Top
回复人: zhaoliang_chen(龙行天下) ( ) 信誉:100 2005-9-24 19:21:34 得分:0
 

URL重写不是PostBack,IsPostBack的值为false是对的
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-24 23:00:13 得分:0
 

上面两位没有理解我的意思,我的意思比如,我希望用户访问的网址是
/1/2/3.aspx
我的实际地址是
/default.asp?a=1&b=2&c=3
我通过错误页面转向功能实现的URL重写,问题是,假如在default.aspx上面有服务器控件,那么在回发的时候就会再次访问/1/2/3.aspx,而这个PostBack同样被再次重写到/default.asp?a=1&b=2&c=3
在这种情况下,Page对象的IsPostBack属性为false,而且也不执行相应的服务器端事件,
怎么才能执行?
其实这应该是一个很复杂的问题,不像上面讲的那么简单来着
Top
回复人: saucer(思归) ( ) 信誉:379 2005-9-25 7:31:10 得分:10
 

are you using .NET 1.*? if so, do you have something like the following in the global.asax?
private void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpContext.Current.RewritePath(HttpContext.Current.Request.RawUrl);
} or show your code
Top
回复人: saucer(思归) ( ) 信誉:379 2005-9-25 7:56:21 得分:0
 

也参考
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 9:54:51 得分:0
 

///以下是我的Error.aspx的代码
///在虚拟主机中设置错误页面转向到Error.aspx
///Dottext.Common.UrlManager.UrlReWriteHandlerFactory就是DotText里面的对象
///想来大家也不陌生吧
if(Request.QueryString!=null)
{
string[] queryString=Server.UrlDecode(Request.QueryString.ToString()).Split(new char[]{';'});
if(queryString.Length==2 && queryString[0]=="404")
{
Uri uri=new Uri(queryString[1]);
this.Context.RewritePath(uri.AbsolutePath,uri.UserInfo,uri.Query);
(new Dottext.Common.UrlManager.UrlReWriteHandlerFactory()).GetHandler(this.Context,Request.RequestType,uri.PathAndQuery,Server.MapPath(uri.LocalPath)).ProcessRequest(this.Context);
this.Context.Response.End();
}
}
Top
回复人: saucer(思归) ( ) 信誉:379 2005-9-26 10:07:19 得分:0
 

不应该用error页面来RewritePath,直接在Application_BeginRequest里做
Top
回复人: saucer(思归) ( ) 信誉:379 2005-9-26 10:08:56 得分:0
 

或者自己写个httpmodule,参考
http://www.codeproject.com/aspnet/dnn2url_rewrite.asp
Top
回复人: saucer(思归) ( ) 信誉:379 2005-9-26 10:11:10 得分:0
 

用Error页是浏览器端的Redirect,请求变成GET,IsPostBack自然变成false了
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 10:13:34 得分:0
 

是啊,这个我也知道,问题是,我用的是虚拟主机,而且管理员钩上了IIS设置中的“检查文件是否存在”,所以对于所有文件,只要不存在物理文件,就不会传递给ASP.NET来处理,那样Application_BeginRequest就没有意义了,
我一直奇怪的是:
一个页面的IsPostBack属性是内部怎么判断的呢?
而服务器端事件又是怎么实现的呢?
这个问题已经超出解决问题的范畴,而升级为技术探讨了,所以我在弄清楚这个之前,不大希望能通过其他的路径解决问题,呵呵
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 10:23:07 得分:0
 

简单的问题搞得复杂而无用,全赖你不预先探讨技术问题。
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 10:27:12 得分:0
 

你现明确你说的回发是什么含意,是否你把重定向叫做回发。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 10:31:16 得分:0
 

不能这么说吧,我觉得这个问题是一个比较值得讨论的技术问题,虽然说解决这个问题本身并不重要,
至于说预先探讨,那我也没有办法,因为Dotext就是这么写的,我要硬拉它到虚拟主机上运行,自然会有些费劲了
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 10:33:48 得分:0
 

不是,我把浏览器把用户的动作(比如点击按钮),发送给服务器以便服务器执行相应的服务器端动作脚本的过程叫做回发,
你这么一问,我倒犹豫了,这个词不会被我用错了吧
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 10:34:50 得分:0
 

机制已经跟你说的很清楚了,你听不进去而已。所谓回发,是指那些通过 http Post命令请求服务器、具有页面的__ViewState、__EventTarget字段以及所有控件的必要的PostData数据的情况。你的代码重定向了到其他页面之后,所有这些数据就不存在与新页面上了。
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 10:39:07 得分:0
 

当你提交一个页面,在完全的asp.net页面内,这个接收页面(你的default.aspx)可以看做回发。但是紧接着你的代码重定向到另一个页面,这另一个页面不能叫做回发,你的3.aspx实际上是 http Get命令被请求的,也就是只有 request.QueryString 还有效,其他都是一个空白初始页面的值。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 10:50:05 得分:0
 

不对,因为我URL重写的时候,并没有只通过网址进行转向,而是将请求的HttpContext一直保留到了最后,实际上我在调试的时候发现,Http的Post和Get数据都还在,可问题是Page页面并不把这些数据当作 回发 来的数据来处理,而以为是第一次请求该页面,因此就出现了问题
注意:Post的数据都还存在
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 10:51:10 得分:0
 

有些人认为 a.aspx 用于显示数据,b.aspx用于修改数据,修改之后再重定向到 a.aspx,或者在页面内重定向到自己作为刷新页面显示的手段,这些都是放弃了 asp.net 的 PostBack 功能了(那么asp.net的各种控件事件机制等也没有什么用),基本上回到了 asp 或 jsp 的那个页面处理层次。
控件是可以动态变化的,只有在 postBack 的时候才能具有状态。页面上往往有上千的状态信息,用url参数是无法写的,所以用 get 方式去组织页面不行。我有个小型的实力程序:http://cmda618.gnway.net/w2cms(北京)或http://cqbd.gnway.net(兰州),你可以看一看在内容大的变化的时候注意url地址栏的变化。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 11:04:00 得分:0
 

对于ASP.NET的页面处理机制,我是这样想的:
当一个访问请求到来,Page对象会判断这个请求是第一次请求还是回发,如果是第一次请求,就会返回相应的页面HTML代码,如果是回发,则根据情况执行相应的服务器端事件代码并返回相应的JS代码改变浏览器内容,
问题在于,我这个页面的Get和Post数据都在的情况下,ASP.NET的Page对象是凭什么判断来认为我的访问不是回发的呢?
我觉得除了Request.RawUrl,其他的应该没有什么不同,如果确实是通过RawUrl来判断的,那通过其他的办法实现的URL重写也会遇到相应的问题了啊
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 11:10:24 得分:0
 

传递一个context怎么就能强求页面认为就是postBack呢?重定向本身就断绝了postBack(根本不是post)。你只能在后一个页面去读取上一个页面传过来的context而已。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 11:20:03 得分:0
 

所以这就值得研究了,在重定向的过程之中,究竟是丢失了什么数据,导致页面不认为是PostBack呢?
在微软我也没有找到关于这个IsPostBack的运行原理的说明
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 11:32:46 得分:40
 

可能我说的不准确,不叫做重定向。你自己看看你获取新页面的机制。
在LoadPageViewState方法中,如果没有回发的__ViewState首先就被判为非isPostBack,然后读取其中含有的上一页面的HashCode,如果与页面的HashCode不相等,就被判为非isPostBack,只有相等了才真正开始处理状态。
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 11:46:25 得分:0
 

哦,刚刚明白你的用意,“我因为使用虚拟主机,无法更改IIS设置”。
我觉着隐藏aspx这个文件后缀这真是自欺欺人,反正我对这个不感兴趣。搜索引擎也并不是对html之类情有独钟,对这些就搞不定,那时多少年前的皇历了。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 16:00:15 得分:0
 

呵呵,是啊,研究这个问题确实有一点感觉在钻牛角尖
不过这个和搜索引擎没有关系,因为我重写的目的不是改变扩展名,而是假设这个文件存在,呵呵
好,先看看你说的LoadPageViewState
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 16:15:18 得分:0
 

我没有仔细看你的代码。刚刚简单看了一下,如果你是“假设这个文件存在”那么你应该是从"1/2/3.aspx"重写到"default.aspx?a=1&b=2&c=3"的,你好像叙述颠倒了。不过也差不多呀。我觉得重写路径一般来说没有太多意义,即使是给我个blog,我也不介意那种url参数的形式。何况我那个程序例子的交互性也说明除非是偶尔欧冲浪者,否则数量的用户不会喜欢打文件地址的形式去找资料,而喜欢在一个“大”的操作方便的画面上去操作。
Top
回复人: sp1234(写几个iframe协同运作都不会的人如今都成Ajax专家了。) ( ) 信誉:100 2005-9-26 16:16:49 得分:0
 

除非是偶尔冲浪者,否则熟练的用户不会喜欢打文件地址的形式去找资料,而喜欢在一个“大”的操作方便的画面上去操作。业务系统更是如此。
Top
回复人: skywatcher(天空守望者) ( ) 信誉:94 2005-9-26 18:41:11 得分:0
 

///问题终于解决了!,感谢sp1234和思归!
///其实方法很简单,就是重写DeterminePostBackMode方法如下
///就实现了手工判断是否有PostBack数据
protected override NameValueCollection DeterminePostBackMode()
{
if(Request.Form.Count>3 && Request.Form.AllKeys[0]=="__EVENTTARGET" &&
Request.Form.AllKeys[1]=="__EVENTARGUMENT" &&
Request.Form.AllKeys[2]=="__VIEWSTATE")
return Request.Form;
else
return null;
}
//函数说明:如果回发使用 POST 方法,则从 Context 对象返回窗体信息。
//如果回发使用 GET 方法,则返回查询字符串信息。
//如果是第一次请求该页,则返回空引用(Visual Basic 中为 Nothing)。
Top

该问题已经结贴 ,得分记录: saucer (10)、 sp1234 (40)、

posted on 2005-09-26 20:33  K_Reverter  阅读(1196)  评论(0编辑  收藏  举报