------------------------------ Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------
127.0.0.7是回环地址(LookBack),就是表示访问本机,LocalHost是它的别名。是无法在外部访问的。查看IP地址:ipconfig
Get和Post的区别:
设定Form的Method属性指定表单提交方式,Get(默认值)是通过URL传递表单值,Post传递的表单值是隐藏到Http报文件中, URL中看不到。
Get和Post的区别:Get是通过URL传递表单值,Post通过URL看不到表单域的值;Get传递的数据量是有限的,如果要传递大量数据不能用Get,比如Type="file"上传文章、Type="password"传递密码或者<textarea>发表大段文章,Post则没有这个限制;Post会有浏览器提示重新提交表单的问题,Get则没有。对于Post的表单位重新敲地址栏再刷新就不会提示重新提交了中,因为重新敲地址就没有偷偷提交的数据了。
Get方式URL数据格式,服务器文件名后跟着“?”,由于客户端可能向服务器端提交多个键值对,键值对之间用“&”进行分割,如果URL中有汉字、特殊符号等,则需要对URL进行编码。
表单域只有设定了Name的才会被提交给服务器(用Get方式看的清楚)。如果给Submit按钮设定Name,那以按钮的Value也会被提交给服务器。
例:
<head>
<title></title>
</head>
<body>
<form action ="Hello.ashx"method="post">
<input type ="hidden"name="ispostback" value ="true" />
用户名:<input type ="text" name="UserName"value="@value" />
<input type ="submit" value ="提交" />
@msg
</form>
</body>
</html>
<%@ WebHandler Language="C#"Class="Hello" %>
using System;
using System.Web;
public class Hello : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/html";
//string username = context.Request["UserName"];
//if (string.IsNullOrEmpty(username))
//{
// context.Response.Write("直接进入");
//}
//else
//{
// context.Response.Write("提交进入");
//}
string username = context.Request["UserName"];
string msg="";
string ispostback = context.Request["ispostback"];
if (ispostback == "true")
{
context.Response.Write("提交进入");
msg = username + "你好!";
}
else
{
context.Response.Write("直接进入");
username = "";
msg = "";
}
string fullpath = context.Server.MapPath("Hello.htm");//得到文件的全路径
string content = System.IO.File.ReadAllText(fullpath);//读取文件
content=content.Replace("@value",username);
content = content.Replace("@msg", msg);
context.Response.Write(content);
}
publicbool IsReusable {
get {
return false;
}
}
}
ViewState初探(重点,常考)
Label版本的值存到了ViewState中,TextBox版本的不用存,因为TextBox就是Input,自己就会提交给服务器,不需要隐藏字段。
用Asp.net重写Div文本自增(还要同时递增Label的宽度,注意Width的单位是Unit类型,不是简单的Int)
Label1.Text=(Convert.ToInt32(Label1.Text)+1).ToString)_;
Label1.Width=new Unit(Label1.Width.Value+10);
查看生成的源代码,ASP.Net将所有隐藏内容统一放到了名字为_VIEWSTATE的隐藏字段中,使用序列化算法将所有隐藏内容放到一个字符串中。点击几次在使用ViewStateDecode这个工具查看ViewState内容,发现了确实将这些改变的内容放到了ViewState中。存储非表单域、非Value值的容器。
禁用ViewState的方法:禁用单个控件的ViewState设定enableviewstate=false,禁用ViewState以后TextBox版本不受影响,Div版本受影响,因为Input的Value不依靠ViewState。禁用整个页面的在Aspx的Page指令加上 EnableViewState="false" 。内网系统、互联网的后台可以尽情的用ViewState。
回答ViewState原理的时候,说Input版本(TextBox)自增和Div版本(Label)的不同。
无状态Http
Http协议是无状态的,不会记得和网页“发生了什么”。服务器不记得上次给了浏览器什么,浏览器需要记信这些值(Input就是记到Value中,对于其他的就要放到隐藏字段中,比如ViewState),下次再提交服务器的时候(请在我的宽度基础上增加了12)就要把上次的值提交给服务器,让它想起来。如果要知道上一次的状态,一个方法是对浏览器响应结束之前将状态信息保存到页面表单中,下次页面再向服务器发出请求的时候带上这些状态信息,这样服务器就能根据这些状态信息还原上次的状态了,类似于去看病的病历本。
状态信息保存在隐藏字段中的缺点:加大网站的流量,降低访问速度,机密数据放到表单中会有数据欺骗等安全性问题。
Cookie
表单是和页面相关的,只有浏览器提交了这些数据服务器端才能得到。而有时候希望在服务器端任意的地方存取一些和访问者相关的信息,这时候就不方便将这些信息保存到表单中了,因为如果那样的话必须随时注意在所有页面表单中都保存这些信息。Cookie是和站点相关的,并且每次向服务请求的时候除了发送表单参数外,还会将和站点相关的所有Cookie都提交给服务器,是强制性的。Cookie也是保存在浏览器端的,而且浏览器会在每次请求的时候都会把这个站点的相关的Cookie提交到服务器,并且将服务器端返回的Cookie更新回数据库,因此可以将信息保存在Cookie中,然后在服务器端读取,修改。服务器返回数据除了普通的Html数据外,还会返回修改的Cookie,浏览器把拿到的Cookie值更新本地浏览器的Cookie就可以。
互联网优化案例:图片服务器和主站域名不一样,降低Cookie流量的传输。
案例:一个页面设置Cookie,一个页面读取Cookie
设置值的页面:Response.SetCookie(new HttpCookie("color",TextBox1.Text));//在客户端也能通过$.cookie取到
读取值的页面: Label1.Text = Request.Cookies["color"].Value;
Cookie的缺点和表单一样,而且还不能存储过多信息。
Session原理
Private int i = 0;////每次请求来了都会New一个新的实现了IHttpHandler接口的类“变量”的实例进行处理,用完了就GC掉,所以不会保持上次的值。(常考)
Cookie不能存储过多信息。如果想保存大量的数据,可以保存一个Guid到Cookie中,然后在服务器中建立一个以Guid为Key,复杂数据为Value全局Dictionary。Static字段对于不同用户也只有一份,因此用Static实现多用户去共享数据。
ASP.Net已经内置了Session机制,把上面的例子用ASP.NetSession重写。不要放太多的对象到Session,Session会有超时销毁机制。服务器不可能知道浏览器是否开着,Cookie和Session都是为了保存和当前客户端相关的数据,不同的是Cookie是存在客户端,用户可以改变。而Session是存在服务器端,客户修改无效。
Session不能放的是object型数据,可任意设置,注意在使用时要做类型转换,不能放太大的数据。
可以看到Session机制并不是Http协议规定的,是ASP.net实现的,现在PHP、JSP等大部分服务端技术都实现了Session,原理都差不多。
建一个名为SessionMgr的类:
public class SessionMgr
{
private static IDictionary<string,IDictionary<string,object>>data =new Dictionary<string,IDictionary<string,object>>();
publicstatic 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;
return session;
}
}
}
在变量.aspx.cs中使用Session。
public partial class Cookie_变量 :System.Web.UI.Page
{
private int i = 0;//每次请求来了都会New一个新的实现了IHttpHandler接口的类“变量”的实例进行处理,用完了就GC掉,所以不会保持上次的值。(常考)
private static int j = 0;//所有访问者都访问同一个J的实例。
protected void Page_Load(object sender, EventArgs e)
{
if (Request.Cookies["MySessionId"] == null)
{
string sessionId = Guid.NewGuid().ToString();
Response.SetCookie(new HttpCookie("MySessionId",sessionId));
}
}
protected void Button1_Click(object sender, EventArgs e)
{
i++;
Label1.Text = i.ToString();
j++;
Label2.Text = j.ToString();
}
protected void Button3_Click(object sender, EventArgs e)
{
string sessionId = Request.Cookies["MySessionId"].Value;
IDictionary<string, object> session =SessionMgr.GetSession(sessionId);
session["服务器端的数据"] = DateTime.Now.ToString();
session["服务器端的另一个数据"] = "我今年24岁了。语速快,激情高,滔滔不绝!";
}
protected void Button2_Click(object sender, EventArgs e)
{
string sessionId = Request.Cookies["MySessionId"].Value;
IDictionary<string, object> session =SessionMgr.GetSession(sessionId);
Button2.Text = Convert.ToString(session["服务器端的数据"])+ session["服务器端的另一个数据"];
}
}
案例:用Session实现验证码。注:HttpHandler要能够操作Session,要实现IRequiresSessionState接口。
以下代码为:验证码.ashx
<%@ WebHandler Language="C#"Class="验证码" %>
using System;
using System.Web;
public class 验证码 :IHttpHandler,System.Web.SessionState.IRequiresSessionState{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/JPEG";
using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(100,50))
{
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
//g.DrawString("computer", new System.Drawing.Font("宋体",20), System.Drawing.Brushes.Blue, new System.Drawing.PointF(0, 0));
//g.DrawEllipse(System.Drawing.Pens.Red, new System.Drawing.Rectangle(10,10, 10, 10));
//System.Drawing.Pen pen =(System.Drawing.Pen)System.Drawing.Pens.Green.Clone();
//pen.Width = 3;
//g.DrawEllipse(pen, newSystem.Drawing.Rectangle(20, 20, 20, 20));
//bitmap.Save(context.Response.OutputStream,System.Drawing.Imaging.ImageFormat.Jpeg);
Random rand = new Random();
int code = rand.Next();
string strCode =code.ToString();
HttpContext.Current.Session["Code"]= strCode;//需在最上面加上System.Web.SessionState.IRequiresSessionState
g.DrawString(strCode, newSystem.Drawing.Font("宋体", 10), System.Drawing.Brushes.Red, newSystem.Drawing.PointF(0, 0));
bitmap.Save(context.Response.OutputStream,System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
public bool IsReusable {
get {
return false;
}
}
}
以下代码为:验证码.aspx(源)
<%@ Page Language="C#"AutoEventWireup="true" CodeFile="验证码.aspx.cs"Inherits="验证码" %>
<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<img src ="验证码.ashx" />
<asp:TextBox ID="TextBox1"runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click"Text="Button" />
</div>
</form>
</body>
</html>
以下代码为:验证码.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class 验证码 :System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
string right = Convert.ToString(Session["Code"]);
if (right == TextBox1.Text)
{
Response.Write("验证码正确");
}
else
{
Response.Write("验证码错误");
}
}
}
Session的目的是为了控制一下内存和当前用户相关的一些数据,但是它存的地方不一样,Cookie存在客户端,Session存在服务器端。以数值自增为例,用Cookie设置自增用户修改后估在其基础上再自增,而用Session设置自增则数值不会随着用户的修改而改变。
机器自动注册
建一个WindowsFormAppcation应用程序,弹出一个Form窗体,在Form1窗体中放一个WebBrowser控件,一个Button,双击Button编写如下代码:
webBrowser1.Document.GetElementById("TextBox1").SetAttribute("Value","地地寺地地地地");
webBrowser1.Document.GetElementById("TextBox2").SetAttribute("Value","woyaozhuuche ");
webBrowser1.Document.GetElementById("Button1").InvokeMember("Click");
用验证码防机器人注册。
Http协议简介:
Web开发是和Http协议打交道的,必须了解Http协议。Http协议版本:Http/0.9、 Http/1.0 、 Http/1.1,现在主流的是Http/1.1版本。
Http协议分析工具:
1、DebugBar,Http(S)标签内容。免费的,只能分析当前浏览器中的内容。
2、Httpwatch,收费的,只能分析当前浏览中的内容,内容更详细,推荐使用。
3、HttpAnalyzer,收费的,能分析计算机上所有的Http请求数据。比如QQ,迅雷等。
Http协议的几个概念:
1,连接(Connection):浏览器和服务器之间传输数据的通道,一般请求完就关闭,不会一直保持连接。
2,请求(Requst):浏览器向服务器发送的“我要……”的消息,包含请求的类型,请求的数据,浏览器的信息(语言、浏览器版本等)。
3,响应(Response):服务器对浏览器请求的返回的数据,包含是否成功,错误码等。
Http是无状态的,不会记得上次的请求,所以哪怕是同一个页面中的JS,CSS,JPG也都要重复提交Accept-language、Accept-Encoding、Cookie等。
Http请求报文:
用httpwatch 查看访问一个网站(用DiscuzNT测试环境)的响应情况。敲入一个网址后,浏览器向服务器发出请求。注意:页面中的图片、JS,CSS在单独的请求中。
GET/HTTP/1.1表示向服务器用GET方式请求首页,使用HTTP/1.1协议。
Accept.Encoding gzip,deflate表示浏览器支持gzip,deflate两种压缩方法。
Accept-language zh-cn表示浏览器支持的语言,很多进入后自动就是中文界面的国际网站就是通过读取这个头的值实现的。
Connection Keep-Alive,则TCP连接在发送后将仍然保持打开状态,于是浏览器可以断续通过相同的连接发送请求。保持续连接节省了为每个请求建立新连接所需的时间,还节约网络带宽。
Cookie是浏览器向服务器发送和当前网站关联的Cookie,这样在服务器也能读取浏览器的Cookie了。
User-Agent为浏览器的版本信息,通过这个信息可以读取浏览器是IE还是FireFox,支持的插件,Net版本等。
Http响应码
浏览器向服务器发出请求,服务器处理可骒是成功,可能是失败,可能没有权限访问等原因,服务器会通过响应码来告诉浏览器处理结果。
"200":OK
"301":Moved Permanently永久转移
"302":Found暂时转移
"307":Temporary Redirect
"400":Bad Requst错误请求
"401":Unalthorized未认证
"403":Forbidden禁止
"404":Not Found未找到
"500":Internal Server Error服务器内部错误,比如在程序中抛异常
"503":Service Unavailable。一般是访问人数过多。
200段是成功,300段需要对请示做进一步的处理。400段表示客户端请求错误。500段是服务器端的错误。
服务器返回的报文:
Sever:Cassini/3.5.0.5表示服务器的类型。
Content-Type:text/html;Charset=utf-8表示返回数据的类型。
服务器通过Content-Type告诉客户端响应的数据的类型,这样浏览器就根据返回数据的类型来进得不同的处理,如果是图片类型就显示,如果是文本类型就直接显示内容,如果用Html类型就用浏览器显示内容,如果是下载类型就弹出下载工具等。
常用Content-Type:Text/HTML、image/GIF,image/jpge,text/plain,text/javascript,application/x-excel,application/octet-stream(二进制文件)
Content-Length:19944表示后续数据消息体的长度,报文头只是描述,返回的具体数据(比如HTML文本,图片数据等)在两个回车之后的内容中。
Http其它
Http是无状态的,不会记得“上个请求”,所以哪怕是同一个页面中的js,css,jpg也都要重复提交Accept-Language,Accept-Encoding,Cookie等等。
页面中如果有图片,css,js等外部文件的话,图片,CSS,JS都在单独的请求中,也就是并不是页面的所有内容都在一个请求中完成,而是每个资源一个请求。
一般情况下,只有浏览器请求服务器端,服务器端才会给浏览器响应数据,不会主动向浏览器推送数据,这样是安全考虑,也是提高服务器的性能考虑。如果要服务器向浏览器推送数据,则需要使用SeverPush等额外的技术。
Http是“请求——响应”的工作方式,因此页面会不断刷新,如果不希望页面刷新则要使用Ajax等技术。
断点续传的原理,多线程下载基于断点续传。
请求响应模型的例子:
按钮实现表格行删除效果;使用超链接进行删除。代码如下:
HTML页代码
<body>
<form action="delete.ashx" id="form1"method ="post">
<input type ="hidden" name="Name" id ="Name" />
<table>
<tr><td>姓名</td><td>性别</td><td>年龄</td><td>操作</td></tr>
<tr><td>黄忠</td><td>男</td><td>24</td><td><ahref ="delete.ashx?Name=黄忠" >删除</a></td></tr>
<tr><td>黄燕</td><td>女</td><td>22</td><td><inputtype ="button" value ="删除"onclick="document.getElementById('Name').value='黄燕';document.getElementById('form1').submit();"/></td></tr>
<tr><td>黄兴</td><td>男</td><td>26</td><td>删除</td></tr>
<tr><td>黄江苗</td><td>男</td><td>6</td><td><ahref ="delete.ashx?Name=黄江苗">删除</a></td></tr>
</table>
</form>
</body>
一般处理程代码.ashx
public class delete : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/html";
string name = context.Request["Name"];
context.Response.Write(name+"已删除");
}
public bool IsReusable {
get {
return false;
}
}
}
这就是Asp.net中数据绑定控件中行按钮和行超链拉实现方式的不同,ListView中Button、HyperLink两种删除方式。按钮方式是将行的ID通过表单提交到服务器,行超链拉的方式是通过超链接的URL通过Get的方式提交给处理页面,超链接的方式由于没有提交所有的表单信息,因此很多服务器端控件的高级用法用不了。
用aspx重写,超链接的因为没有向服务器提交ViewState等隐藏字段,所以处理时IsPostBack为False,而按钮的则是提交了表单,所以IsPostBack为Ture。代码如下:
用Web窗体重写delete.aspx
body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1"runat="server"></asp:TextBox>
<input type ="hidden"name="Name"id="Name" />
<div>
<table>
<tr><td>姓名</td><td>性别</td><td>年龄</td><td>操作</td></tr>
<tr><td>黄忠</td><td>男</td><td>24</td><td><ahref ="用Web窗体重写delete.aspx?Name=黄忠" >删除</a></td></tr>
<tr><td>黄燕</td><td>女</td><td>22</td><td><inputtype ="button" value ="删除"onclick="document.getElementById('Name').value='黄燕';document.getElementById('form1').submit();"/></td></tr>
<tr><td>黄兴</td><td>男</td><td>26</td><td>删除</td></tr>
<tr><td>黄江苗</td><td>男</td><td>6</td><td><ahref ="用Web窗体重写delete.aspx?Name=黄江苗">删除</a></td></tr>
</table>
</div>
</form>
</body>
用Web窗体重写delete.aspx.cs
public partial class 请求响应_用Web窗体重写delete :System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)//这行不要,则超链接均works,button NO works
{
string name = Request["Name"];
Response.Write(name + "已删除");
}
}
}
Web开发的一些基本原则:
最小权限原则。只允许用户做……而不是“不允许用户做什么……
浏览器查看的是服务器端代码的执行输出的文,除非服务器有漏洞,否则浏览者无法查看服务器端的aspx、cs代码,目标另存为也是保存的aspx的执行结果,而看不到aspx的源代码。js、html是被输出到浏览器上执行的,因此无法禁止浏览者查看js,html。
能在浏览器端完成的事情,就不要到服务器端去做。
客户端是不可信的。
C#代码是运行在服务器端的,JS代码是运行在浏览器客户端的。
按钮确认提交的实现在Button的OnClientClick中写<input type="submit" name="Button1"value="delete" onclick="return confirm("确定要删除吗?");"id="Button1" />代码是运行在浏览器端的,和服务器端没有关系。
在服务器端“弹出消息窗口”
Response.Write("<script type='text/javascript'>alert('你点了我');</script>");并不是真的在服务器端运行的,只是生成了Javascript代码到浏览器端,浏览器会在解析文档时运行alert,不推荐用这种写法,读懂即可,推荐用后面讲的RegisterClientStartupScript。只是渲染到浏览器端,所以并不会行到对话框关闭服务器端的代码才会执行下去(在Response.Write("<script type ='text/javascript'>alert('你点了我');</script>");后设置断点)
对于服务器端的代码来说,生成一堆HTML代码就是一堆字符串,没有任何意义,只有到了浏览器端执行才有意义。
客户端验证不能代替服务器端验证
设置取款金额不能高于100元
客户端:<form id="form1"runat="server"onsubmit="if(parseInt(document.getElementById('TextBox1').value,10)>100){alert('最多只能取100');returnfalse;}">注:出错啦!!!!!!!!!!!!!!!!!!
服务器端:Label1.Text = "取款金额为:" + TextBox1.Text;
如果禁用JavaScript(Internet选项——安全——自定义级别——脚本——活动脚本——禁用,用maxthon里的【内容控制】——【禁用JavaScript】进行控制。那么客户端JavaScript校验就被禁用了,就可以取款多于100元了。
解决方法:在服务器端也进行数据校验。
客户端校验是为了很好的客户端体验,服务器端校验是最后一次把关,防止恶意请求。后面要讲的ASP.NetValidation就是ASP.Net内置的数据校验技术,会在客户端和服务器端同时校验。
对Button来讲,onclick是服务器端代码,OnClientClick是最终生成到客户端浏览器中的onclick代码。
---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ---------------------- 详细请查看:http://net.itheima.com/