首页 > 代码库 > HTTP中Get与Post、ViewState 原理

HTTP中Get与Post、ViewState 原理

Http是请求,响应的模型,服务器不会来读取浏览器的网页,只能够得到客户端提交过来的数据
当用户点击提交,服务器就知道"提交回来了"(PostBack)

Get与Post


设置form的method属性指定表单提交方式,get(默认值)是通过URL传递值,传递的数据量是有限的
post传递的表单值是隐藏到http报文中,URL中看不到,会有浏览器提示重新提交表单的问题,get没有
Get方式URL数据格式,服务端文件名跟着"?",由于客户端可能向服务器端提交多个键值对,
键值对之间用"&"进行分割,如果URL中有汉字,特殊符号等,则需要对URL进行编码
表单域只有设定了name的才会被提交给服务器

网页只有设定了name的input,textarea,select的value属性值才会被提交给服务器
非表单元素无法将值传递给服务器的
如:要设置DIV的值,直接是不行的,可以通过隐藏字段实现,将隐藏字段的value与DIV的内容设置成一样
然后当用户提交信息,服务器获得隐藏字段的值,并把值 替换掉网页所有的 value

如果指定from 表单method属性为get,那么在 action=1.ashx?a=123的参数就会被删除
如如果指定为post,那么action中的参数就会被提交到服务器来

ViewState 原理 (对于上面问题的解决办法)

Label版本的值存到了ViewState中,TextBox版本的不用存,因为TextBox就是Input,自己就会提交给服务器,不需要隐藏字段.
用于asp.net重写DIV文本自增(还要同时递增Label的宽度,注意Width的单位)
Label1.Text = (Convert.ToInt32(Label1.Text)+1).ToString();
Label1.Width = new Unit(Label1.Width.Value + 10);
查看生成的源代码,ASP.net将所有隐藏内容统一放到了名字为__VIEWSTATE的隐藏字段中,使用序列化
算法将所有隐藏的内容放到一个字符串中,点击几次在使用ViewStateDecoder这个工具查看ViewState
内容,发现确实将这些改变的内容放到了ViewState中

禁用ViewState的方法:在页面最上面 Page标签 加入 EnableViewstate="false",禁用ViewState以后
TextBox版本不受影响,DIV版本受影响,因为input的value不依靠ViewState(可以禁用单个控件)
禁用ViewState后并不是完全去掉ViewState,还会有一小段代码,如果想在页面中完全没有ViewState
那么在页面中就不能有 runat=server的form,如果Button等服务端控件没有放到runat=server的form
中,那么则是不用的

回答ViewState原理的时候说:input版本(TextBox)自增和DIV版本(Label)的不同

--------- ViewState 使用:

     // 在后台为 ViewState 赋值          this.ViewState["key"] = "004";          this.ViewState.Add("key2", 360);     // 调用 ViewState    Label1.Text = this.ViewState["key"].ToString();

只要有runat=server的form就会产生 _VIEWSTATE等,所以去掉form的runat=server,这样除了Repeater等少数控件之外服务端控件都没法使用,只能使用html标签。
这是为什么说"要求高的互联网项目不用服务端控件"

无状态HTTP

1.HTTP协议是无状态的,不会记得上次和网页"发生了什么",如果要知道上一次的状态,
一个方法就是在对浏览器响应结束之前将状态信息保存到页面表单中,下次页面再向服务器发出请求的
时候带上这些状态信息,这样服务器就能根据这些状态信息还原上次的状态了
2.状态信息保存在隐藏字段中的缺点:加大网站的流量,降低访问速度,机密数据放到表单中会有数据欺骗等安全问题

原因:HTTP是用的TCP协议,为了降低服务器的消耗,当服务器响应完客户端后,就立马段掉,所以无状态

ASP.NET保存状态有以下几种:

Application 当前应用程序(所有用户使用一个Application)
Session 当前会话(每个用户一个会话)
Cookie 保存在客户端的
ViewState 针对当前页面(每个页面有一个ViewState)

一、Application 对象

Application是全局的,保存与操作都放在服务器端,任何人都能访问

使用 object 保存
this.Application["t1"] = TextBox1.Text;
Application.Lock(); //锁定
Application.UnLock(); //解锁

可以在 Global.asax 中对网页的访问量,点击量 做一些统计

二、Cookie的使用

Cookie存在客户端
Cookie是和站点相关的,并且每次向服务器请求的时候除了发送表单参数外,还会将和站点相关的所有
Cookie都提交给服务器,是强制性的,Cookie也是保存在浏览器端的,而且浏览器会在每次请求的时候都
会把和这个站点相关的Cookie提交到服务器,并将服务端返回的Cookie更新回数据库,因此可以将信息
保存Cookie中,然后在服务器端读取,修改.
服务器返回数据除了普通的html数据以外,还会返回修改后的Cookie,浏览器把拿到的Cookie值更新本地
浏览器的Cookie就可以

设置:

Response.SetCookie(new HttpCookie("Color",TextBox1.Text));

Response.Cookies.Add(new HttpCookie("Size","22"));

读取:

Lable1.Text = Request.Cookies["Color"].Value;

扩展使用:

HttpCookie h1 = new HttpCookie("Color", TextBox1.Text);    //创建一个Cookie对象 h1.Expires = DateTime.Now.AddHours(1);    //设置过期时间,只能用DateTime格式h1.HttpOnly = true;    //设置客户端是否能够访问脚本Response.SetCookie(h1);    //设置CookieResponse.AppendCookie();    //追加Cookie

Cookie的缺点和表单一样,不能存储过多的信息.

网站优化案例:
网站的图片服务器要与主站域名不一样,降低Cookie流量的传输
注意:图片,CSS,JS等静态文件,都是单独请求中

如果一个网站有 多个图的话,本地又有那个网站的 cookie 的话,
那么访问时,请求HTML 有传一次 Cookie, 请求每张图片都要再传 cookie ,这样就浪费了。。
如果设置 图片服务器的域名和 主站的不一样的话,当下载图片的时候就不会传 cookie 了,
因为 cookie 是不可以跨域的!!

三、Session原理

Session存放在服务器端,存放的是object类型
private int i = 0; //每次请求来了都会new一个新的实现了IHttpHandler接口的类"变量"的实例,
进行处理,用完了就GC掉,所以不会保持上次的值,所以不会自增
private static int j = 0; // static不会被实例化,所有访问者都访问同一个J的实例,
仍然保存上次的值,所以会自增
Cookie不能存储过多信息,如果想保存大量的数据,可以保存一个Guid到Cookie中,然后在服务器中建立一个以Guid为Key,复杂数据为Value全局Dictionary,static 字段对于不同用户也只有一份,

因此用static实现多用户共享数据,代码如下:

public class sessionMgr        //session管理页面{    private static IDictionary<string,IDictionary<string, object>> data = http://www.mamicode.com/new Dictionary<string,IDictionary<string,object>>();    public static IDictionary<string, object> GetSession(string sessionId)    {        if (data.ContainsKey(sessionId))        {            return data[sessionId];        }        else        {            IDictionary<string, object> session = new Dictionary<string, object>();            data[sessionId] = session;        //为data增加value ,sessionId为KEY,session为value            return session;        }    }   }    protected void Page_Load(object sender, EventArgs e)  //加载事件    {        if (Request.Cookies["MySessionId"] == null)    //判断是否有MySessionId,没则增加        {            string sessionId = Guid.NewGuid().ToString();            Response.SetCookie(new HttpCookie("MySessionId", sessionId));        }    }    protected void btus_Click(object sender, EventArgs e) //设置Session单击事件    {        string sessionId = Request.Cookies["MySessionId"].Value;        IDictionary<string, object> session = sessionMgr.GetSession(sessionId);        session["服务端的数据"] = DateTime.Now;  //添加键值    }    protected void butd_Click(object sender, EventArgs e)  //读取Session单击事件    {        string sessionId = Request.Cookies["MySessionId"].Value;        IDictionary<string, object> session = sessionMgr.GetSession(sessionId);        butd.Text = Convert.ToString(session["服务端的数据"]);    }

ASP.net已经内置了Session机制,把上面的例子用ASP.NetSession重写,
注意:不要放太多的对象到Session,Session会有超时销毁的机制
可以看到Session机制并不是HTTP协议规定的,是ASP.NET实现的,现在PHP,JSP等大部分服务端技术都
实现了Session,原理都差不多
如果当用户禁用了 Session ,可以在 Web.conf 中的 <system.web>里面增加属性,使得将SeesionID保存到 URL 中,<sessionState cookieless="UseUri" />

ASP.NET内置的 Session

Session["one"] = DateTime.Now;            //设值Label1.Text =Convert.ToString(Session["one"]);    //取值

 

HTTP中Get与Post、ViewState 原理