HttpServletRequest的应用(一)
HttpServletRequest简介
WEB客户端发送给WEB服务器的HTTP请求消息分为三个部分:
请求行 POST /demo/login HTTP/1.1
请求消息头
消息正文(也叫实体内容) username=xxxx&password=1234
Servlet API中定义的ServletRequest接口类用于封装请求消息。
HttpServletRequest是专用于HTTP协议的ServletRequest子接口,它用于封装HTT请求消息。
在service()方法内部调用HttpServletRequest对象的各种方法来获取请求消息。
获取请求行的相关信息
HTTP请求消息的请求行包括请求方式、资源路径和HTTP协议版本:
GET/it315/servlet/RequestURI?param1=a¶m2=b HTTP/1.1
getMethod方法返回HTTP请求消息中的请求方式。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getProtocol方法返回请求行中的协议名和版本。
getContextPath方法返回请求资源所属于的WEB应用程序的路径。
getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
getPathTranslated方法返回URL中的额外路径信息所对应的资源的真实路径。
getServletPath方法返回Servlet的名称或Servlet所映射的路径。
获取网络连接信息
getRemoteAddr方法返回发出请求的客户机的IP地址,其格式为“192.168.0.3”这种形式的字符文本。 (*)
getRemoteHost方法返回发出请求的客户机的完整主机名,即“pc1.it315.org”这种格式。
getRemotePort方法返回发出请求的客户机所使用的网络接口的端口号。
getLocalAddr方法返回WEB服务器上接收当前请求的网络接口的IP地址。
getLocalName方法返回WEB服务器上接收当前请求的网络接口的IP地址所对应的主机名。
getLocalPort方法返回WEB服务器上接收当前请求的网络接口的端口号。
getServerName方法返回当前请求所指向的主机名。
getServerPort方法返回当前请求所连接的服务器端口号。
getScheme方法返回请求的协议名,例如http、https或ftp。
getRequestURL方法返回客户端发出请求时的完整URL。
获取请求头信息的各种方法
getHeader方法
getHeaders方法
getHeaderNames方法
getIntHeader方法
getDateHeader方法
getContentType方法
getContentLength方法
getCharacterEncoding方法
获取所有请求头的编程例子
Enumeration headerNames =request.getHeaderNames();
while(headerNames.hasMoreElements())
{
String headerName =(String)headerNames.nextElement();
out.print(headerName + " : "+ request.getHeader(headerName) + "<br>");
/*如果要考虑同一个请求头名可能出现多次,
那么应该用下面的代码段代替上面一行程序代码*/
/*Enumeration values =request.getHeaders(headerName);
while(values.hasMoreElements())
{
out.print(headerName + ": " + (String)values.nextElement() + "<br>");
}*/
}
利用Referer请求头阻止“盗链”
Stringreferrer = request.getHeader("referer");
StringsitePart = "http://" + request.getServerName();
if(referrer!=null&& referrer.startsWith(sitePart))
{
//处理正当的下载请求,这里只进行示意
out.println("dealing download...");
}
else
{
//非法下载请求跳转到本站的下载说明页
RequestDispatcher rd =request.getRequestDispatcher("/down.html");
rd.forward(request,response);
}
利用Referer请求头隐藏JavaScript源码
Stringreferrer = request.getHeader("referer");
StringsitePart = "http://" + request.getServerName();
if(referrer!=null&& referrer.startsWith(sitePart))
{
//向客户端输出javascript的document.write(...)语句
out.println(
"document.write('假设这是很多重要的Javascript代码的执行结果');");
}
客户端身份认证实践
StringencodedAuth = request.getHeader("Authorization");
//要求客户端发送身份认证信息,并且只能是BASIC认证方式中
if(encodedAuth == null ||!encodedAuth.toUpperCase().startsWith("BASIC"))
{
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setHeader("WWW-Authenticate","BASICrealm=\"it315\"");
//当用户单击登录框中的“取消”按钮时,将输出下面的内容
out.println("没有传递用户身份!");
return ;
}
使用GET方式传递参数
在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET。
如果网页中的<form>表单元素的method属性被设置为了“GET”,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET。
使用GET请求方式给WEB服务器传递参数的格式:
http://www.vshoping.tk/counter.jsp?name=zhangsan&password=123
使用GET方式传送的数据量一般限制在1KB以下。
使用POST方式传递参数
POST请求方式主要用于向WEB服务器端程序提交FORM表单中的数据。
POST方式将各个表单字段元素及其数据作为HTTP消息的实体内容发送给WEB服务器,传送的数据量要比使用GET方式传送的数据量大得多。
<form>表单元素的enctype属性用于指定浏览器使用哪种编码方法将表单中的数据传送给WEB服务器,该属性可以有两种取值:
application/x-www-form-urlencoded
multipart/form-data
POST请求消息的格式:
POST /counter.jspHTTP/1.1
referer:http://localhost:8080/Register.html
content-type: application/x-www-form-urlencoded
host: localhost:8080
content-length: 43
name=zhangsan&password=123
提交、重置、普通按钮如何传送参数
在一个FORM表单中可以有多个提交按钮,单击任何一个提交按钮都可以提交表单,只有被单击的提交按钮的名称和值才被作为参数传递,其它提交按钮的信息不会作为参数传递。
表单中的普通按钮与重置按钮的名称和值不会作为参数传递。
没有设置name属性的表单字段元素的信息不会作为参数传递。
单行与多行文本输入框如何传送参数
不管单行和多行文本输入框中是否有内容,设置了name属性的文本输入框的信息总是会作为参数传递。如果文本框中没有输入内容,可以认为其内容为一个空字符串(“”),其参数形式为“text1=”。
单选按钮与复选框如何传送参数
只有被选中的复选框和单选按钮的信息才会作为参数传递,未被选中的复选框和单选按钮的信息不会作为参数传递。
对于多个名称相同的复选框,它们可以同时被选中;对于多个名称相同的单选按钮,只能同时选中其中的任意一个。
对于被选中的多个同名复选框,它们的信息将以多个名称相同的参数进行传递,即参数列表中会出现多个名称相同的参数。
对于没有设置value属性的单选按钮和复选框,当它们被选中时,它们传递的默认参数值为“on”。
使用Javascript防止重复提交表单
<script>
varisCommitted = false;
functioncheckPost()
{
if(!isCommitted)
{
isCommitted = true;
return true;
}
else
{
alert("不能重复提交表单");
return false;
}
}
</script>
<formaction="servlet/RepeateFormServlet" method="POST"onsubmit="return checkPost()">
分析文件上传的请求消息结构
ServletInputStreamsis = request.getInputStream();
StringfilePath = getServletContext().getRealPath("/body.out");
FileOutputStreamfos = new FileOutputStream(filePath);
byte[]buf = new byte[1024];
intlen = sis.read(buf,0,1024);
while(len!= -1)
{
fos.write(buf,0,len);
len = sis.read(buf,0,1024);
}
fos.close();
sis.close();
了解中文字符的URL编码
publicstatic String encode(String s,String enc) throwsUnsupportedEncodingException
publicstatic String decode(String s,String enc) throwsUnsupportedEncodingException
getInputStream与getReader方法
getInputStream 方法用于返回的一个代表实体内容的输入流对象,其类型为javax.servlet.ServletInputStream。
getReader方法用于返回的一个代表实体内容的BufferedReader对象,返回的BufferedReader对象将实体内容中的字节数据按照请求消息中指定的字符集编码转换成文本字符串。
在调用getReader方法之前,可以调用ServletRequest的setCharacterEncoding方法指定其返回的BufferedReader对象所使用的字符集编码。
最后一些注意的事项:
如果提交FORM表单的页面与处理表单请求的Servlet程序都是由同一个人或同一个项目组开发的,那么只要在处理表单提交的Servlet程序中将传递给setCharacterEncoding方法的字符集编码设置为该表单所在页面的字符集编码即可。
如果Servlet程序可以接收来自多个其他站点的FORM表单提交的数据,而每个其他站点的页面所采用的字符集编码可能各不一样,要想让Servlet程序知道FORM表单内容的字符集编码,可以在FORM表单中增加一个隐藏字段来传递当前FORM内容的字符集编码名称。
只要超链接、FORM表单的action属性设置、请求转发和重定向的URL等任何一种请求路径中要包含参数,就必须对参数部分进行URL编码。对参数进行URL编码时所选择的字符集编码应尽量与当前页面的字符集编码保持一致,也可以用一个参数来指定URL编码内容的字符集编码名称。
所有标准的浏览器和客户机终端都支持UTF-8编码,如果WEB服务器要能兼容处理各个国家和地区版本的浏览器所传递的FORM表单信息,网页文档应当使用UTF-8编码格式。
在编写应用程序时应该注意一些隐性的字符编码错误。有些程序在输出时有编码转换错误,在读取输入时返回的字符串也有转换错误,当该程序输出它所读取到的有问题的字符串时,显示的结果可能是正常的中文字符