Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >页面状态保持机制(编辑中)

页面状态保持机制(编辑中)

作者头像
用户1075292
发布于 2018-01-23 03:52:10
发布于 2018-01-23 03:52:10
1.2K00
代码可运行
举报
文章被收录于专栏:听雨堂听雨堂
运行总次数:0
代码可运行

Web应用程序中,有很多状态需要在页面的反复回调中能够保持住,还有一些状态需要在页面之间保持。对于状态的保持,是一个值得研究的问题。状态处理不当是页面失效或错误的一个重要的原因。

对于ASPX页面来说,控件可以通过VIEWSTATE来保持状态。VIEWSTATE机制非常好用,有时甚至可以用来保存页面后台代码中属性变量的状态值:因为变量的状态在回调时是不保存的,但是控件的状态却可以保持,因此可以通过控件来保持变量的状态,把控件设置为隐藏状态就不影响页面显示了。

但是VIEWSTATE却不能包打天下,我们的很多页面处理,都是以URL调用的方式进行的,如分页浏览,每次通过分页器进行的跳转都是新开页面,无法使用VIEWSTATE。

分页处理中,使用了URL参数来传递状态,这种传递方式简单明了,但也存在问题:

1、复杂。需要在URL中把各种状态全部写进去,一个都不能少。参数数量众多,考虑不周往往容易遗漏,还不好找原因。

2、和其他方式之间的协调问题。因为页面本身可能有回调操作,比如查询,或者其他的需要回调页面的控件操作,URL参数和回调参数之间的协调必须要精确的处理好。

特别是第二点,在分页浏览中体现得非常明显:既要能在不指定查询条件的情况下浏览所有数据,又要能够支持在回调事件中处理查询操作,还要能够把查询条件传递给新的分页器。要实现这一要求,只能借助复杂的处理逻辑来实现了。

这种需要在URL中传递所有参数的方式,在构造分页器链接的时候需要把页面所需的参数都显式地进行传递。当页面还有其他参数,特别是和分页无关的参数的时候,就会很难控制。构造分页器时,要去解析和分页无关的参数,要进行参数集合重复性的判断以及决定究竟哪个参数有效等。这些操作对于分页处理程序而言,既不合理也是隐患多多的。

基于页面的参数保持机制

参数传递的种种不便之处,使人不禁想到,为什么非要使用URL呢?URL方式,适合传递一些变化的参数。而上述的问题,都是由于一些需要保持的参数的传递而引起的。对于参数的保持,还有更加合适的手段:如Session或者Cookie。

那么,究竟选择Cookie还是Session呢?Session是一个进程级别的状态保存机制,在整个浏览过程中,在打开的所有页面之间,Session保存的数据都会有效。但Session也存在不足:

1、Session存放在服务器端,占用服务器的资源;

2、多个页面公用Session变量,容易导致混乱,如果每个页面都分别创建Session变量,则又造成资源的浪费;

3、Session本身有失效周期,在一些需要长期打开工作的页面,带来页面失效问题。

而Cookie相对来说,正好没有Session的不足。首先,Cookie不占用服务器资源,其次,Cookie按键-值的方式存储,正好可以用每个页面的名称为key,存储每个页面的状态。

根据各种应用的需要,基于页面的状态保持机制应该达到如下的要求:

1、页面回调时保持状态

2、页面跳转时保持状态

3、以Cookie方式存储数据

4、通过索引器的方式访问

5、兼容各种状态机制,自动尝试从URL、Session、Cookie中获取需要的参数值

6、只要使用过的参数,自动保持到Cookie中

页面状态保存机制的实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// WebPage 的摘要说明
///    用于网页的参数的缓存,可以将多种类型的参数缓存起来:以Url中的参数权限最高。URL中的参数会自动保存在Cookie(以网页名称命名)中,每次可以自动加载Cookie。
///    非缓存参数,可以用Querystring来访问。
/// </summary>
public class WebPara
{
	Page page;  //所在的网页
	private Dictionary<string, string> Paras = new Dictionary<string, string>();
	string strPage;
	/// <summary>
	/// 构造函数
	/// </summary>
	public WebPara()
	{
		page = (Page)HttpContext.Current.Handler;
		init();
	}
	/// <summary>
	/// 构造
	/// </summary>
	/// <param name="WebPage"></param>
	public WebPara(Page WebPage)
	{
		page = WebPage;
		init();
	}

	void init()  //初始化
	{
		strPage = System.Text.RegularExpressions.Regex.Match(page.Request.FilePath, "(?<=/)[^/]*Aspx", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Value.ToLower();  //页面统一为小写,cookie区分大小写

		//从cookie中加载所有的参数
		HttpCookie ParaCookie = page.Request.Cookies[strPage];  //以页面命名的Cookie
		if (ParaCookie != null)
		{
			for (int i = 0; i < ParaCookie.Values.AllKeys.Length; i++)
			{
				string parakey = ParaCookie.Values.AllKeys[i];
				Paras.Add(parakey.ToLower(),HttpUtility.UrlDecode(ParaCookie[parakey]));
			}
		}

		//从URL中覆盖加载参数
		for (int i = 0; i < page.Request.QueryString.Count; i++)
		{
			if (Paras.ContainsKey(page.Request.QueryString.GetKey(i).ToLower()))   //变量统一用小写
			{
				Paras[page.Request.QueryString.GetKey(i).ToLower()] = page.Request.QueryString[i];
			}
			else
				Paras.Add(page.Request.QueryString.GetKey(i).ToLower(), page.Request.QueryString[i]);
		}

		//回写所有参数到Cookie中
		foreach (KeyValuePair<string, string> kvp in Paras)
		{
			page.Response.Cookies[strPage][kvp.Key] = HttpUtility.UrlEncode(kvp.Value);
			page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(30);
		}
		//page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(1);  //保存一天
	}
	/// <summary>
	/// 参数索引。写入时,如果参数已经存在,则覆盖,否则创建
	/// </summary>
	/// <param name="ParaName"></param>
	/// <returns></returns>
	public string this[string ParaName]
	{   
		get
		{
			if (Paras.ContainsKey(ParaName.ToLower()))
			{
				return Paras[ParaName.ToLower()];
			}
			return "";
		}
		set  //有则覆盖,没有就添加
		{
			if (Paras.ContainsKey(ParaName.ToLower()))
			{
				Paras[ParaName.ToLower()] = value;
			}
			else
				Paras.Add(ParaName.ToLower(), value);

			//回写
			page.Response.Cookies[strPage][ParaName.ToLower()] = HttpUtility.UrlEncode(value);
			page.Response.Cookies[strPage].Expires = DateTime.Now.AddDays(30);

			//page.Response.Cookies[strPage][ParaName.ToLower()] = value;
		}
	}

	/// <summary>
	/// querystring中的变量,不存在则返回空
	/// </summary>
	/// <param name="ParaName"></param>
	/// <returns></returns>
	public string QueryString(string ParaName)
	{
		return StringUtil.ToStr(page.Request.QueryString[ParaName]);
	}
	/// <summary>
	/// 所有参数的信息
	/// </summary>
	/// <returns></returns>
	public string AllInfo()
	{
		string ret="";
		foreach (KeyValuePair<string, string> kvp in Paras)
		{
			ret += kvp.Key + ":" + kvp.Value + "\r\n";
		}
		return ret;
	}

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014-05-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
20道前端高频面试题(附答案)_2023-03-02
then只会捕获第一个成功的方法,其他的函数虽然还会继续执行,但是不是被then捕获了。
aync_sync
2023/03/02
4840
社招前端常见面试题(附答案)
Math.pow(2, 53) ,53 为有效数字,会发生截断,等于 JS 能支持的最大数字。
bb_xiaxia1998
2022/09/13
5300
阿里前端常见面试题(附答案)
但是这些a标签可能包含一些像span、img等元素,如果点击到了这些a标签中的元素,就不会触发click事件,因为事件绑定上在a标签元素上,而触发这些内部的元素时,e.target指向的是触发click事件的元素(span、img等其他元素)。
coder2028
2022/09/13
4510
2022秋招前端面试题(九)(附答案)
可以看到修改原型的时候p的构造函数不是指向Person了,因为直接给Person的原型对象直接用对象赋值时,它的构造函数指向的了根构造函数Object,所以这时候p.constructor === Object ,而不是p.constructor === Person。要想成立,就要用constructor指回来:
helloworld1024
2022/08/10
2.7K0
美团前端二面面试题_2023-02-28
JavaScript中Number.MAX_SAFE_INTEGER表示最⼤安全数字,计算结果是9007199254740991,即在这个数范围内不会出现精度丢失(⼩数除外)。但是⼀旦超过这个范围,js就会出现计算不准确的情况,这在⼤数计算的时候不得不依靠⼀些第三⽅库进⾏解决,因此官⽅提出了BigInt来解决此问题。
用户10357900
2023/02/28
4800
滴滴前端一面经典手写面试题
一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了
helloworld1024
2023/01/04
9230
前端二面经典面试题指南_2023-02-28
XSS 攻击指的是跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。
用户10377405
2023/02/28
4800
那些高级前端是如何回答面试题的_2023-02-24
这个问题相信很多人会第一时间想到 Promise.all ,但是这个函数有一个局限在于如果失败一次就返回了,直接这样实现会有点问题,需要变通下。以下是两种实现思路
gogo2027
2023/02/24
5420
年底前端面试题总结(上)
HTTP1.0 中默认是在每次请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接,这就是短连接。当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接,这就是长连接。其使用方法如下:
loveX001
2022/10/11
7950
腾讯前端一面必会面试题合集
解构是 ES6 提供的一种新的提取数据的模式,这种模式能够从对象或数组里有针对性地拿到想要的数值。 1)数组的解构 在解构数组时,以元素的位置为匹配条件来提取想要的数据的:
loveX001
2022/09/13
4540
2023我的前端面试小结3
事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件委托(事件代理)。
loveX001
2023/01/05
7140
2023前端二面经典手写面试题_2023-02-27
题目描述:有一组版本号如下 ['0.1.1', '2.3.3', '0.302.1', '4.2', '4.3.5', '4.3.4.5']。现在需要对其进行排序,排序的结果为 ['4.3.5','4.3.4.5','2.3.3','0.302.1','0.1.1']
用户10358576
2023/02/27
5550
字节前端高频面试题
JSONP 核心原理:script 标签不受同源策略约束,所以可以用来进行跨域请求,优点是兼容性好,但是只能用于 GET 请求;
helloworld1024
2022/09/12
3360
前端经典面试题(有答案)4
解析: 因为constructor是prototype上的属性,所以dog.constructor实际上就是指向Dog.prototype.constructor;constructor属性指向构造函数。instanceof而实际检测的是类型是否在实例的原型链上。
loveX001
2023/01/06
4640
2023我的前端面试小结3
首屏时间的计算,可以由 Native WebView 提供的类似 onload 的方法实现,在 ios 下对应的是 webViewDidFinishLoad,在 android 下对应的是onPageFinished事件。
loveX001
2023/01/05
5310
高级前端二面面试题
不会继承,因为根据 this 绑定四大规则,new 绑定的优先级高于 bind 显示绑定,通过 new 进行构造函数调用时,会创建一个新对象,这个新对象会代替 bind 的对象绑定,作为此函数的 this,并且在此函数没有返回对象的情况下,返回这个新建的对象
夏天的味道123
2022/09/12
4840
腾讯前端必会面试题合集
闭包是一种特殊的对象,它由两部分组成:执行上下文(代号 A),以及在该执行上下文中创建的函数 (代号 B),当 B 执行时,如果访问了 A 中变量对象的值,那么闭包就会产生,且在 Chrome 中使用这个执行上下文 A 的函数名代指闭包。
yyzzabc123
2022/09/12
4100
京东前端一面高频面试题(附答案)
(1)block: 会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;
bb_xiaxia1998
2022/09/07
5250
前端常见面试题总结_2023-02-23
以下是代码实现,实现了思路,但是可能会存在 Bug,但是这种设计题一般是给出设计思路和部分代码,不会需要写出一个无问题的代码
var_1024
2023/02/23
7880
社招前端一面经典手写面试题集锦
String.prototype.padStart 和 String.prototype.padEnd是ES8中新增的方法,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。我们先看下使用语法:
helloworld1024
2022/09/17
3960
相关推荐
20道前端高频面试题(附答案)_2023-03-02
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验