深入体验JavaWeb开发内幕核心基础3.docx
- 文档编号:10827750
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:37
- 大小:137.53KB
深入体验JavaWeb开发内幕核心基础3.docx
《深入体验JavaWeb开发内幕核心基础3.docx》由会员分享,可在线阅读,更多相关《深入体验JavaWeb开发内幕核心基础3.docx(37页珍藏版)》请在冰豆网上搜索。
深入体验JavaWeb开发内幕核心基础3
声明:
如果引用或借鉴本书稿中的图例、解说和讲解技巧,请标明出处,以示对我的辛勤劳动的尊重!
这些东西虽然谈不上创造发明,但确实也是花费了我很多时间和精力去总结、归纳出来的。
如果有人等我总结、消化后再“巧妙借鉴”,精华和核心全部拿走,然后在随便从书上找到别的知识作补充,以示区别的行为将会极大挫伤我的积极性,希望网友们从道义上对这种行为进行谴责!
因涉及商业机密和出版合同,本书中的一些最富有技巧的知识和讲解手法没有提供出来,敬请谅解!
————张孝祥
第7章会话与状态管理
7.2.1什么是Cookie
Cookie是一种在客户端保持HTTP状态信息的技术,它好比商场发放的优惠卡。
顾客在一个商场购物结账离开时,商场可以决定是否赠送给顾客一张优惠卡,不同顾客的优惠卡上记载的信息可以不同,例如,记载该顾客累计购物的金额和有效期限。
顾客可以决定是否接受这张优惠卡,一旦顾客接受了这张优惠卡,那么他在以后每次光顾该商场时,都将携带这张优惠卡,商场也将根据这张优惠卡上记载的信息进行一些特殊的事务处理,例如,计算折扣率和累加本次购物金额。
Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一片数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。
浏览器可以决定是否保存这片数据,一旦WEB浏览器保存了这片数据,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这片数据回传给WEB服务器。
显然,Cookie最先是由WEB服务器发出的,是否发送Cookie和发送的Cookie的具体内容,完全是由WEB服务器决定的。
WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个WEB站点可以给一个WEB浏览器发送多个Cookie,这样,在WEB浏览器和WEB服务器之间就可以使用多个Cookie来传递多种信息,例如,用一个Cookie来标识访问者的姓名,用另外一个Cookie来标识该用户登录站点的次数。
一个Cookie除了有名称和设置值外,它还可以有一些其他的附加属性,例如,Cookie的有效时间。
如果设置了Cookie的有效时间,接受它的浏览器进程将该Cookie保存在计算机硬盘中,只有该Cookie超出有效时间后才被删除,这样的Cookie将被同一台计算机上启动的多个浏览器进程共享。
正如一个顾客可以有多家商场提供的优惠卡一样,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
为了防止Cookie塞满客户机的硬盘,浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
如果没有设置Cookie的有效时间,接受它的浏览器进程只将该Cookie保存在自己的内存空间中,在该浏览器进程关闭时,它里面保存的所有Cookie也将随之消失。
Cookie在浏览器与WEB服务器之间传送的过程如图7.1所示。
图7.1
Cookie实现了一种在浏览器和服务器之间产生有状态会话的方式,它可以把一个浏览器访问的同一个服务器上的所有程序贯连起来,在这些程序之间传递数据。
例如,当用户使用浏览器访问某个网站的登录程序进行登录后,无论这个浏览器再访问该网站的哪个程序,其他程序都能知道访问者的身份信息,这是在WEB站点中非常普遍的一个应用。
这种应用通常就是采用Cookie技术来实现的,当WEB服务器程序验证登录请求中的用户名和密码后,产生一个标识该用户身份的标识号,然后在响应消息中将该标识号以Cookie的形式传递给浏览器,浏览器在以后每次访问该WEB服务器时,都自动在请求消息头中将标识号又以Cookie的形式返回给WEB服务器,凭借浏览器返回的标识号,WEB服务器的其他程序就能分辨出当前请求是由哪个用户发出的。
但是,有一点要注意,不保存在硬盘中的Cookie信息是否可以被同一台计算机上启动的多个浏览器进程共享,不同的浏览器有不同的处理方式。
对于IE浏览器来说,保存在其中一个浏览器进程的内存空间中的Cookie是不能被其他浏览器进程共享的,这就会出现同一台计算机上的每个浏览器进程都会与服务器形成各自独立的会话;而对于MozillaFirefox浏览器来说,所有的进程和标签页都共享cookie信息。
另外,在IE浏览器中按Ctrl-N键(或者单击“文件”“新建”“窗口”菜单)打开的窗口或者是用javascript的window.open语句打开的窗口,都会共享原窗口的Cookie信息,因为它们属于同一个浏览器进程内部的多个窗口。
7.5.3利用Session实现一次性验证码
一些人为了窃取他人在某个网站上的帐号,通常采用的办法就是在网站登录页面中不断尝试各种密码进行登录,如果纯粹采用手工方式,由于劳动强度和效率的问题,他们最终都会由于收获渺茫而放弃。
但是,如果这些人借用自动化的密码猜测工具来无限制地尝试各种密码,他们成功窃取别人密码的可能性就非常大了。
一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理和编程实现与7.5.3节的利用Session防止表单重复提交的例子程序基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。
为了不给正常用户添加太多的输入麻烦,验证码不能太长,通常为4个随机的字符。
为了增加其他工具程序自动识别出验证码的难度,识别码通常以图片的形式展示给用户,并在图片中随机产生一些杂乱的干扰点,如图7.25所示。
图7.25
服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。
验证码使用一次即失效,用户只能重新向服务器发出访问表单填写页面的请求来获得新的验证码,并填写新的验证码后才能再次提交有效的表单请求,这样将大大增加了用户重复操作的难度。
密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。
下面编写一个利用Session实现一次性验证码的例子程序,整个程序包含三个组件:
check_code.html、CheckCodeServlet.java和LogonFormServlet.java。
check_code.html是引用验证码图片的FORM表单页面,CheckCodeServlet.java是用于产生带有随机验证码图片的Servlet程序,LogonFormServlet.java则是负责处理FORM表单请求的Servlet程序。
动手体验:
利用Session实现一次性验证码
(1)按上面描述的功能编写如例程7-11、例程7-12和例程7-13所示的程序。
例程7-11check_code.html
带有验证码的登录页面
用户名:
密码:
验证码:
例程7-12CheckCodeServlet.java
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjava.awt.*;
importjava.awt.image.*;
importjavax.imageio.ImageIO;
publicclassCheckCodeServletextendsHttpServlet
{
privatestaticintWIDTH=60;
privatestaticintHEIGHT=20;
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException
{
HttpSessionsession=request.getSession();
response.setContentType("image/jpeg");
ServletOutputStreamsos=response.getOutputStream();
//设置浏览器不要缓存此图片
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
//创建内存图象并获得其图形上下文
BufferedImageimage=
newBufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
Graphicsg=image.getGraphics();
//产生随机的认证码
char[]rands=generateCheckCode();
//产生图像
drawBackground(g);
drawRands(g,rands);
//结束图像的绘制过程,完成图像
g.dispose();
//将图像输出到客户端
ByteArrayOutputStreambos=newByteArrayOutputStream();
ImageIO.write(image,"JPEG",bos);
byte[]buf=bos.toByteArray();
response.setContentLength(buf.length);
//下面的语句也可写成:
bos.writeTo(sos);
sos.write(buf);
bos.close();
sos.close();
//将当前验证码存入到Session中
session.setAttribute("check_code",newString(rands));
//直接使用下面的代码将有问题,Session对象必须在提交响应前获得
//request.getSession().setAttribute("check_code",newString(rands));
}
privatechar[]generateCheckCode()
{
//定义验证码的字符表
Stringchars="0123456789abcdefghijklmnopqrstuvwxyz";
char[]rands=newchar[4];
for(inti=0;i<4;i++)
{
intrand=(int)(Math.random()*36);
rands[i]=chars.charAt(rand);
}
returnrands;
}
privatevoiddrawRands(Graphicsg,char[]rands)
{
g.setColor(Color.BLACK);
g.setFont(newFont(null,Font.ITALIC|Font.BOLD,18));
//在不同的高度上输出验证码的每个字符
g.drawString(""+rands[0],1,17);
g.drawString(""+rands[1],16,15);
g.drawString(""+rands[2],31,18);
g.drawString(""+rands[3],46,16);
System.out.println(rands);
}
privatevoiddrawBackground(Graphicsg)
{
//画背景
g.setColor(newColor(0xDCDCDC));
g.fillRect(0,0,WIDTH,HEIGHT);
//随机产生120个干扰点
for(inti=0;i<120;i++)
{
intx=(int)(Math.random()*WIDTH);
inty=(int)(Math.random()*HEIGHT);
intred=(int)(Math.random()*255);
intgreen=(int)(Math.random()*255);
intblue=(int)(Math.random()*255);
g.setColor(newColor(red,green,blue));
g.drawOval(x,y,1,0);
}
}
}
例程7-13LogonFormServlet.java
importjava.io.*;
importjavax.servlet.*;
importjavax.servlet.http.*;
publicclassLogonFormServletextendsHttpServlet
{
publicvoidservice(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,IOException
{
response.setContentType("text/html;charset=GB2312");
PrintWriterout=response.getWriter();
HttpSessionsession=request.getSession(false);
if(session==null)
{
out.println("验证码处理问题!
");
return;
}
StringsavedCode=(String)session.getAttribute("check_code");
if(savedCode==null)
{
out.println("验证码处理问题!
");
return;
}
StringcheckCode=request.getParameter("check_code");
if(!
savedCode.equals(checkCode))
{
/*验证码未通过,不从Session中清除原来的验证码,
以便用户可以后退回登录页面继续使用原来的验证码进行登录*/
out.println("验证码无效!
");
return;
}
/*验证码检查通过后,从Session中清除原来的验证码,
以防用户后退回登录页面继续使用原来的验证码进行登录*/
session.removeAttribute("check_code");
out.println("验证码通过,服务器正在校验用户名和密码!
");
}
}
编译上面的两个Java源文件,确保编译后生成的class文件存放在了
将check_code.html文件保存在
(2)在
在web.xml文件中的相应位置处增加如下两段内容:
……
保存web.xml文件后,重新启动Tomcat。
(3)在浏览器地址栏中输入如下地址:
http:
//localhost:
8080/it315/check_code.html
浏览器中显示出如图7.25所示的效果,然后就可以对验证码的功能进行测试了。
多学两招:
用时间间隔限制用户连续发帖
验证码除了可以用在用户登录页面中以抵御密码猜测工具外,也可以用在一些发表评论的页面中来防止用户故意使用工具连续向服务器重复提交信息的行为。
但是验证码方式也不能有效阻止捣乱者采用手工方式连续发送垃圾信息的行为,因为用户只要重新向服务器发出访问表单填写页面的请求而获得新的验证码,就可以再次向服务器提交信息。
一些网站通常采用在Session中记录用户发帖的时间,然后通过一个时间间隔来限制用户连续发帖的数量。
第8章JSP
8.1.6JSP与JavaScript的综合应用
JavaScript是由浏览器解释执行的程序代码,它是网页内容的一部分,主要用于在网页上产生动态的显示效果和实现与用户的交互功能。
JSP程序则是由WEB服务器解释执行的程序代码,它用于产生供浏览器显示的网页内容。
由于JavaScript代码属于网页的内容部分,所以,JavaScript代码也可以通过JSP页面输出。
JavaScript和JSP的关系犹如HTML代码和JSP的关系,即JavaScript代码是JSP程序输出的一段可以被浏览器解释执行的特殊文本内容。
只要先写好一个包含有JavaScript代码的网页文档,然后将这个网页文档的内容改为用JSP程序输出,这样就可以一下子明白JSP与JavaScript的区别和应用关系了。
动手体验:
JSP与JavaScript的综合应用
(1)在一个WEB邮件系统中,当用户打开邮箱的收件夹时,其中的所有邮件标题将在一个网页中列出,如图8.5所示。
图8.5
用户可以选中某些邮件,然后对其执行删除、移动等操作。
要标识邮件的选中状态,通常都是在每个邮件旁边放置一个复选框,用户选中某个复选框,即表示用户要选中它旁边的邮件。
另外,为了方便用户通过一次操作就选中所有的邮件,网页中通常都要放置一个全选复选框,当选中这个全选复选框时,所有的邮件复选框也随之被自动选中,当去掉全选复选框的选中状态时,所有的邮件复选框的选中状态也随之被去掉。
要想通过单击图8.5中的“全选”复选框来一次操作就选中所有的邮件,显然需要用一段JavaScript代码来实现。
由于邮箱中的邮件数目是不确定的,因此图8.5中的代表每封邮件的复选框的个数也是不确定的,它们通常是由ASP、JSP等服务器端程序动态产生的,在这种情况下,如果为每个复选框都设置一个不同的名称,每个复选框在程序中的引用名称也就各不一样,这样,要通过JavaScript将每个复选框设置为选中状态时,不可能用一段循环代码来统一处理所有的复选框,而要为每个复选框的都编写单独的处理程序代码。
较好的做法是为每个复选框都设置一个完全相同的名称,但它们各自的设置值不同,分别代表每封邮件的编号,这样,在JavaScript中就可以用一个数组来访问这些复选框,从而可以使用一段循环语句来对每个复选框进行处理。
另外,将每个复选框的名称都设置成一样,也有利于服务器端程序通过简单的代码就可获知客户端所选中的多封邮件。
例程8-6是一个模拟图8.5中的“全选”复选框功能的HTML文件,其中的JavaScript代码细节请参看笔者的《JavaScript网页开发》一书。
例程8-6maillist.html
functioncheckAll()
{
varcount=document.mailForm.mail.length;
for(vari=0;i { document.mailForm.mail[i].checked= document.mailForm.ifAll.checked; } } 用浏览器直接打开例程8-6所示的maillist.html文件,单击“全选”复选框,可以看到所有其他的复选框也随之被选中。 (2)在实际应用中,某个邮箱的收件夹中可能有多封邮件,也可能只有一封邮件,甚至是一封邮件都没有,而上面的maillist.html文件中的JavaScript代码不能正确处理只有一封邮件和一封邮件都没有的情况。 修改maillist.html文件,将其中的与邮件2和邮件3相关的语句注释掉,如下所示: …
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 深入 体验 JavaWeb 开发 内幕 核心 基础