上一篇分享了一些关于web入门的知识点,在分享Http协议之前,还要特别强调下servlet的内容。
我们在web工程里创建的大多都是servlet文件,创建步骤如下:
1.创建web-project
2.右键创建servlet 创建class类 继承httpServlet
在 web.xml文件中系统会自动配置如下内容
<servlet>
<servlet-name>servlet的名称 任意</servlet-name>
<servlet-class>servlet的包名.类名</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet的名称 任意</servlet-name>
<url-pattern>/映射名称</url-pattern>
</servlet-mapping>
这里应该注意两个<servlet-name>中的名称是相同的, <url-pattern>中系统默认为“/servlet/映射名称",为了访问方便直接改为“/映射名称”即可。
3.重写servlet的doGet()方法
4.访问servlet 必须部署到tomcat服务器中
http://localhost:8080/项目名称/servlet的映射名称
下面进入本文正题:
一.Http协议入门
1.什么是Http协议
Http协议:对浏览器客户端与服务器端之间数据传输格式的规范
2. 查看http协议工具
上文提到过,这里建议使用谷歌浏览器,右键"检查"--network查看即可
3.协议内容
请求:是从浏览器到服务器
GET /Day04/index.jsp HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=DCD3D121ACF1576775761B4EECCD3E44
响应:是从服务器到浏览器
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 622
Date: Mon, 13 Mar 2017 00:59:14 GMT
二.请求
GET /Day04/index.jsp HTTP/1.1 --请求行
Host: localhost:8080 --请求头(多个key-value对象)
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: JSESSIONID=DCD3D121ACF1576775761B4EECCD3E44
--空行
name=jack&password=123456 --(可选) 实体内容
1.请求行
GET /Day04/index.jsp HTTP/1.1
HTTP/1.1指的是协议版本 http1.0版本当浏览器客户端与服务器建立连接后,只能发出一次请求,一次请求后连接关闭
http1.1版本在建立连接后,可以在一次连接中发送多次请求
/Day04/index.jsp 指的是请求资源
这里有两个很相似的东东 URL :统一资源定位符 用来定位网址, 例如http://localhost:8080/Day04/01testImage.html
URI : 统一资源标示符 用来标记任何资源,可以是本地资源,也可以网络资源
GET 指的是请求方式
常见的请求方式有很多种,不仅仅是我们常用的get和post两种。
我们曾经在html的表单提交程序中也见过这两位的身影:
<form method="get/post" action="表单提交地址">
</form>
除了GET和POST之外,请求方式还有HEAD PUT DELETE CONNECT TRACE
下面这个问题很关键:
get和post请求方式的区别?
1)get请求 在地址栏uri中会拼接提交的参数 ?开始 如果存在多个&分割
2)get请求提交的参数不能超过1kb
3)get方式不适合提交敏感数据
1)post提交请求参数 封装到请求实体中 不存在? 如果存在多个&分割
2)post提交的参数没有限制
3)post提交敏感数据 (加密)
这里可能有人会有疑问,get招谁惹谁了,为啥不能提交敏感数据呢
用下面这个代码试一试就清楚了
<!DOCTYPE html>
<html>
<head>
<title>测试两种请求方式</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<h3>get请求方式</h3>
<form action="02testMethod.html" method="get">
用户名:<input type="text" name="name"><br>
密码:<input type="password" name="pwd"><br>
<input type="submit" value="提交">
</form>
<h3>post请求方式</h3>
<form action="/Day04/RequestDemo1" method="post">
用户名:<input type="text" name="name"><br>
密码:<input type="password" name="pwd"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
使用get方式会在地址框内看到自己刚刚输入提交的内容,这看起来太尴尬了
刚刚输入的Tom和123都显示在了地址栏内············
2.请求头
Host: localhost:8080 --(必须)当前请求访问的目标地址(主机:端口)
Connection: keep-alive --浏览器与服务器的连接状态 keep-alive 保持连接 close 关闭连接
Cache-Control: max-age=0 --缓存控制
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
--浏览器接收的数据的类型
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
--浏览器类型
Accept-Encoding: gzip, deflate, sdch --浏览器接收的数据压缩格式
Accept-Language: zh-CN,zh;q=0.8 --浏览器接收的语言
Cookie: JSESSIONID=DCD3D121ACF1576775761B4EECCD3E44
3.实体内容
post请求方式提交的数据
4. HttpServletRequest
这玩意是干嘛的呢?当然是用来获得请求数据的啦
下面介绍一下 HttpServletRequest 的核心API
请求行:
request.getMethod() 获得请求方式
request.getRequestUri() 获得请求资源
request.getProtocol() 获得 协议版本
请求头:
request.getHeader("名称") 根据指定的名称获取具体的值
Enumeration<String> it=request.getHeaderNames(); 获取所有的请求头的名称 ,Enumeration用法同迭代器
实体内容:只有post提交时才具有实体内容
request.getInputStream() 获得实体内容
光看核心API那绝对是谁看谁蒙圈,在程序员的道路上永远都得自己动手敲一敲实际看一看才能彻底理解
那我们就创建个servlet文件来看一看呗
/**
* 请求获取数据
*/
public class RequestDemo1 extends HttpServlet {
/**
* 1)tomcat服务器接收浏览器发送的数据 然后将请求的数据封装到HttpServletRequest对象中
* 2)tomcat调用doGet()方法时 然后将request对象传递给doget()方法使用
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 3)从request对象中获取请求数据
*/
//method1(request);//请求行数据
method2(request);
}
private void method2(HttpServletRequest request){
/**
* 3.2 请求头数据
*/
String host=request.getHeader("Host");
System.out.println(host);
Enumeration<String> it=request.getHeaderNames();//获取请求头中所有的名称
while(it.hasMoreElements()){//hasNext()
String heardName=it.nextElement();//next()
String heardValue=request.getHeader(heardName);
System.out.println(heardName+"====="+heardValue);
}
}
private void method1(HttpServletRequest request){
/**
* 3.1 请求行数据 格式(GET /Day04/index.jsp HTTP/1.1 请求方式 请求资源 http协议版本)
*/
System.out.println("请求方方式:"+request.getMethod());
System.out.println("请求资源:"+request.getRequestURI());
System.out.println("请求资源:"+request.getRequestURL());
System.out.println("http协议版本:"+request.getProtocol());
}
//当浏览器以post方式访问服务器时调用的方法
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 3.1 实体内容数据 实体内容中存放的是post提交的数据
*/
InputStream input=request.getInputStream();//得到实体内容
byte[] buff=new byte[1024];
int temp=0;
while((temp=input.read(buff))!=-1){
String str=new String(buff,0,temp);
System.out.println(str);
}
}
}
可能看了上面的代码还是蒙圈,首先我们在一个servlet文件中需要重写doGet()和doPost方法,就他俩常用
doGet()中有两个方法,分别请求头和请求行,用到了上面列举的方法。
获取请求头数据中的Enumeration的使用方法是不是很像迭代器?什么,不知道迭代器?小小参考一下Java的集合章节吧
实体内容在post中才有,按上面代码即可获取到,这段代码是不是也有点似曾相识呢?
在浏览器访问该servlet文件,即可在控制台看到获取到相应的的结果,下图为部分结果:
掌握了这些核心API的应用方法,我们来看几个小案例呗
5.案例-获取浏览器类型
这个案例十分简单,用request.getHeader("名称")得到了User-Agent来判断你正在使用什么浏览器。
/**
* 案例-获取浏览器类型
*/
public class RequestDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");//编码
//User-Agent 请求头中可以获取浏览器的类型
String userAgent=request.getHeader("User-Agent");
System.out.println(userAgent);
//判断浏览器的类型
if(userAgent.contains("Chrome")){
response.getWriter().write("你正在使用谷歌浏览器");
}else if("Trident".equals(userAgent)){
response.getWriter().write("你正在使用IE浏览器");
}else{
response.getWriter().write("暂不支持");
}
}
}
当你用谷歌浏览器访问该Servlet文件时,你会看到对应的输出结果:
6.案例-防止非法链接
这个案例同样是使用request.getHeader("名称")获取到referer,来判断当前的请求来自何处,得到这个信息对该请求来源进行判断来确定下一步要做什么
/**
* 案例-防止非法连接
*/
public class RequestDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");//编码
//referer 当前的请求来自于哪里
String referer=request.getHeader("referer");
System.out.println("referer="+referer);
/**
* 判断是否属于非法连接
* 1)referer是null
* 2)referer是否来自广告页
*/
if(referer==null || !referer.contains("/Day04/adv.html")){
//非法连接
response.getWriter().write("当前是非法连接 请回到广告页<a href='/Day04/adv.html'>广告页</a>");
}else{
//正确的
response.getWriter().write("正在下载....");
}
}
}
最开始获得到的refer信息为null,按照条件来说即为非法链接,所以访问该servlet文件可以看到:
这里使用了一个标签,链接到一个网页,这个网页由自己建立:
<!DOCTYPE html>
<html>
<head>
<title>广告页</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
广告内容,猛戳这里 <br>
<a href="/Day04/RequestDemo3">点击此处下载</a>
</body>
</html>
其实这个网页很简单,又重新链接回我们访问的servlet文件,这个时候我们得到的referer就不为null了,而是我们刚刚的地址,不满足非法链接的判断条件,所以就弹出另外一个页面:进入下载页面
7.传递的请求参数如何获取
这是本篇文章的的重点内容,必须会敲相应的代码
上面我们提到过通过GET方式,参数会拼接到uri地址后,通过POST方式:参数会在实体内容中。
获取get方式的参数:request.getQueryString();
获取post方式的参数:InputStream input=request.getInputStream();
下面我们来看核心API:
request.getParameter("name属性的值"); 根据参数中指定的name获取指定的值
Enumeration<String> enums=request.getParameterNames(); 获取表单中所有的参数对应的值
String[] request.getParameterValues("name属性的值"); 根据name获取多个value值 比如我们之间接触的表单中的checkbox就可以使用此方法
在显示的过程中,我们常常会遇到出现乱码的状况,我们我可以用下面这条代码解决此问题:
request.setCharacterEncoding("utf-8"); 设置为utf-8
下面我们动手写一些代码来体验一下这些API的作用:
首先呢,我们还是先建立一个html文件:
<!DOCTYPE html>
<html>
<head>
<title>测试获取请求参数</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<h3>get请求方式</h3>
<form action="/Day04/RequestDemo4" method="get"><!--/Day04/RequestDemo4?name=xx&pwd=xx -->
用户名:<input type="text" name="userName"><br>
密码:<input type="password" name="pwd"><br>
性别:
<input type="radio" name="gender" value="man">男
<input type="radio" name="gender" value="woman">女<br>
籍贯:
<select name="jiguan">
<option>大连</option>
<option>沈阳</option>
<option>抚顺</option>
</select><br>
爱好:
<input type="checkbox" name="hobby" value="lq">篮球
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="code">敲代码<br>
个人简介:
<textarea rows="5" cols="20" name="info"></textarea><br>
<!-- 隐藏域 -->
<input type="hidden" name="id" value="001"><br>
<input type="submit" value="提交">
</form>
<hr/>
<h3>post请求方式</h3>
<form action="/Day04/RequestDemo4" method="post">
用户名:<input type="text" name="userName"><br>
密码:<input type="password" name="pwd"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
这个程序一看就知道什么功能了吧,我们一会就是要在这样的一个界面中输入我们要提交的数据,然后用上面的那些方法来获取:
下面我们来看一下获取的程序,还是和之前一样,建立一个servlet文件:
/**
* 获取传递的请求参数
*/
public class RequestDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置全局编码
request.setCharacterEncoding("utf-8");
/**
* 通用方法获取请求参数
* getParameter("需要获取的参数的name属性值")
*/
String name=request.getParameter("userName");
String password=request.getParameter("pwd");
System.out.println("name="+name+",password="+password);
System.out.println("=======================================");
//getParameterNames() 根据名称name获取所有的请求参数的值
Enumeration<String> enums=request.getParameterNames();
while(enums.hasMoreElements()){
String paramName=enums.nextElement();
if("hobby".equals(paramName)){
//getParameterValues() 根据请求参数名称获取数组
String[] hobbys=request.getParameterValues(paramName);
for(String s:hobbys){
System.out.println(s+",");
}
}else{
String paramValue=request.getParameter(paramName);
System.out.println(paramName+"----"+paramValue);
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//一定要调用doGet()即可
this.doGet(req, resp);
}
}
爱好hobby的类型就是之前提到的那个checkbox类型,同时获取多个数据,所以我们在程序里判断一下如果是爱好一栏,我们使用
String[] request.getParameterValues("name属性的值"); 这个方法建立数组来获取
我们在get部分的区域填写内容时,相应的内容即会打印到控制台上:
我们除了观察这个之外,还需要注意的是我们获取的是html文件中对应的哪个name 或者value,学习编程需要多多总结
在dopost()方法里我们需要写上this.doget(xx,xx),即可共用doget()中的方法,这样就能获取相应的数据了。
同理,我们在post区域输入内容后,也会在控制台打印如下结果:
前面这几篇分享都很基础也很简单,练习几遍就可掌握。