1.http协议
1.1 概念
是对浏览器和服务器端数据传输格式的规范!
1.2 http协议内容
请求
GET /bbs/hello HTTP/1.1 # 请求行
Host: localhost:8080 # 请求头
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: Pycharm-bdfc5fce=39c67252-c198-4d9b-bafc-ce7c50022791
响应
Content-Length: 46
Content-Type: text/html;charset=utf-8
Date: Mon, 08 Jul 2019 08:01:07 GMT
2.1 请求行
GET /day08/first HTTP/1.1
http协议版本:
http1.0: 当浏览器和服务器连接之后,在一次连接中只能发出一个请求
http1.1:当浏览器和服务器连接之后,在一次连接中可以发出多次请求。(效率比1.0更高)
常见问题:
在一个html页面,在页面上有三张图片,访问这个html页面,问一共发出几次请求?
答案:4次
请求资源:请求服务器的哪个资源文件
/day08/first : URI: 统一资源描述符。可以描述任何文件,本地,互联网
http://localhsot:8080/day08/first:URL : 统一资源定位符,互联网(基于http协议) ,是URI的子集。
请求方式(提交方式):
http协议中的请求方式:GET、POST、HEAD、PUT、CONNECT。。。。
最常用的的请求方式: GET 和 POST
<form action="提交的地址" method="get/post">
</form>
GET:
1)提交的参数显示到地址栏
原理: get方式提交的参数会跟在请求行内容的URI后面。以?开始,每个参数使用=号分开,name=jacky,第二个参数之后使用&符合连接
GET /day08/testMethod.html?name=jacky&password=123456 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-GB,en-US;q=0.8,zh-CN;q=0.6,zh;q=0.4,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day08/testMethod.html Connection: keep-alive
2)不适合存放敏感数据
3)不超过1kb
POST:
1)提交的参数不会显示到地址栏
原理:post提交的参数跟在请求的实体内容中。第二个参数用&连接
POST /day08/testMethod.html HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-GB,en-US;q=0.8,zh-CN;q=0.6,zh;q=0.4,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day08/testMethod.html Connection: keep-alive name=jacky&password=123456 -实体内容
2)适合敏感数据
3)提交的大小没有限制
2.2 请求头
Accept: text/html,image/* --浏览器接受的数据类型
Accept-Charset: ISO-8859-1 --浏览器接受数据编码格式
Accept-Encoding: gzip,compress --浏览器接受的数据压缩格式
Accept-Language: en-us,zh- ---浏览器接受的语言
Host: www.it315.org:80 --请求发出的主机和端口(必须)
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT --浏览器缓存的最后修改时间
Referer: http://www.it315.org/index.jsp -- 当前请求来自于哪里 (防止非法链接)
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) --浏览器的类型
Cookie:name=eric ---浏览器保存的cookie数据
Connection: close/Keep-Alive ---浏览器和服务器的连接状态。close:关闭。keep-alive:保持连接
Date: Tue, 11 Jul 2000 18:23:51 GMT --请求发出的时间
package cn.jxufe.b_servlet; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 使用HttpServletRequest获取请求的信息 * * @author Administrator * */ /** * 使用HttpServletRequest获取请求信息 * @author APPle * HttpServletRequest对象:获取请求数据 * 请求行: * 请求方式: request.getMethod() * 请求资源: request.getRequestURI() / request.getRequestURL() * http协议版本: request.getProtocol(); * 请求头 * request.getHeader("name") * request.getHeaderNames() * 实体内容: * request.getInputStream(); */ public class RequestDemo1 extends HttpServlet { // 1)tomcat服务器接收到浏览器发送的请求数据 // 2)tomcat服务器把请求数据封装成HttpServletRequest对象 // 3)tomcat服务器调用doGet方法,把request对象传入servlet public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 4)通过request对象获取请求数据 t1(request); t2(request); } // doPost接受post提交的请求 @Override protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException { t3(request); } private void t3(HttpServletRequest request) throws IOException { System.out.println("t3--------------------"); // 4.3 实体内容 // 注意: post提交的参数才会出现在实体内容中 InputStream in = request.getInputStream(); byte[] buf = new byte[1024]; int len = 0; while ((len = in.read(buf)) != -1) { String str = new String(buf, 0, len); System.out.print(str); } } private void t1(HttpServletRequest request) { // 4.1 请求行 // 请求方式 System.out.println("t1----------------"); System.out.println("请求方式:" + request.getMethod()); // 请求资源 System.out.println("URI:" + request.getRequestURI()); System.out.println("URL:" + request.getRequestURL()); // http协议版本 System.out.println("Http协议:" + request.getProtocol()); } private void t2(HttpServletRequest request) { System.out.println("t2--------------------"); // 4.2 请求头 String value = request.getHeader("host");// 根据头名称获取头值 System.out.println("host:" + value); System.out.println("========================================"); // 遍历所有头 Enumeration<String> enums = request.getHeaderNames();// 获取所有头名称 while (enums.hasMoreElements()) { String headerName = enums.nextElement(); String headerValue = request.getHeader(headerName); System.out.println(headerName + ":" + headerValue); } } }
2.3 案例- user-agent头 -- 获取浏览器类型
package cn.jxufe.b_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 案例【user-agent】 浏览器类型 */ public class RequestDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); String userAgent = request.getHeader("user-agent"); // System.out.println(userAgent); if (userAgent.contains("Firefox")) { response.getWriter().write("你正在使用火狐浏览器"); } else if (userAgent.contains("Chrome")) { response.getWriter().write("你正在使用谷歌浏览器"); } else if (userAgent.contains("Trident")) { response.getWriter().write("你正在是IE浏览器"); } else { response.getWriter().write("识别不了的浏览器"); } } }
2.4 案例- referer头 --- 防止非法链接
第一次:下载资源 - > 下载页面 -> 打开广告页面(下载链接) -> 开始下载
第二次:直接点击下载链接 -> 跳转广告页面(下载链接) -> 开始下载
非法请求:
1)直接访问下载资源
2)不是从广告页面过来的请求
referer请求头只有从超链接过来的请求才有这个头
package cn.jxufe.b_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RequestDemo4 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.contains("adv.html") ) */ if (referer == null || !referer.contains("/adv.html")) { response.getWriter().write("你当前请求是非法请求,请转到首页。<a href='/bbs/adv.html'>首页</a>"); } else { response.getWriter().write("资源正在下载....."); } } }
2.5 获取参数数据
get: 放在请求行的URI后面
post: 放在请求的实体内容
reuqest.getParameter("name") 获取一个值的参数
request.getParameterValue("name") 获取多个值的参数
request.getParameterNames() 获取所有参数名称
request.getParameterMap() 获取所有参数对象
package cn.jxufe.b_servlet; import java.io.IOException; import java.util.Collection; import java.util.Enumeration; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 案例【获取请求的参数数据】 */ public class RequestDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); /* * 获取get提交的参数.(URI后面的参数数据) */ String params = request.getQueryString(); System.out.println(params); /** * 问题: * 1)获取到的参数数据,还需要进一步处理,获取参数值 * 2)两种提交方式的获取代码完全不一样的,不通用。 */ /** * 通用的获取参数的方法:(无论get和post可用) * reuqest.getParameter("name") 获取一个值的参数 * request.getParameterValue("name") 获取多个值的参数 * request.getParameterNames() 获取所有参数名称 * request.getParameterMap() 获取所有参数对象 */ System.out.println("通过参数获取----------------------"); String name = request.getParameter("name"); System.out.println(name); String password = request.getParameter("password"); System.out.println(password); System.out.println("遍历所有参数----------------------------"); // 遍历所有的参数 Enumeration<String> enums = request.getParameterNames();// 获取所有参数名称列表 while (enums.hasMoreElements()) { String paramName = enums.nextElement(); String paramValue = request.getParameter(paramName); System.out.println(paramName + "=" + paramValue); } System.out.println("获取参数对象列名(Map集合)------------------"); Map<String, String[]> map = request.getParameterMap(); // 获取参数对象列名(Map集合) /** * 每个map的对象就是一个参数(包含参数名称和参数值) * key: 参数名称 * value: 参数值(默认情况下都是多个值的参数) */ /** * 复习Map集合 * 问题: Map集合如何遍历? * 1)entrySet() * 2)keySet() * 3) values() */ // 1)entrySet()方法:获取键值对对象的Set集合 // Entry对象中包含一个键对象,和一个值对象 System.out.println("map方式1:"); Set<Entry<String, String[]>> entrySet = map.entrySet(); for (Entry<String, String[]> entry : entrySet) { // 获取键对象 String key = entry.getKey(); // 获取值对象(数组的第一个元素就是参数值) String[] value = entry.getValue(); System.out.println(key + "=" + value[0]); } // 2)keySet(): 获取所有键对象的Set集合 System.out.println("map方式2:"); Set<String> keySet = map.keySet(); for (String key : keySet) { // 通过键对象获取值对象 String[] value = map.get(key); System.out.println(key + "=" + value[0]); } System.out.println("map方式3:"); // 3)values(): 获取所有值对象的Collection集合(只能获取值对象,不能获取键对象) Collection<String[]> values = map.values(); for (String[] value : values) { System.out.println(value[0]); } System.out.println("根据参数名称获取多个参数值:-----------"); String[] hobits = request.getParameterValues("hobit"); // 根据参数名称获取多个参数值 for (String h : hobits) { System.out.print(h + ","); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 获取post提交的参数(实体内容中) */ ServletInputStream in = request.getInputStream(); byte[] buf = new byte[1024]; int len = 0; while ((len = in.read(buf)) != -1) { String str = new String(buf, 0, len); System.out.print(str); } // 在doPost方法中调用doGet里面的逻辑代码 doGet(request, response); } }
3.Http响应
3.1 响应行
http协议版本
状态码:当前服务器处理请求的状态(结果)
常见的状态码:
200 : 请求处理完成,成功返回!
02: 需要浏览器进一步请求,才能完成。
404: 浏览器端的错误。没有找到资源。
500: 服务器端的错误。
状态描述:对状态码的文字补充
3.2 响应头
Location: http://www.it315.org/index.jsp --重定向的地址。结合302状态使用完成重定向的效果
Server:apache tomcat --服务器的类型
Content-Encoding: gzip --服务器发送给浏览器的数据压缩格式
Content-Length: 80 --服务器发送给浏览器的数据长度
Content-Language: zh-cn --服务器支持语言
Content-Type: text/html; charset=GB2312 --服务器发送给浏览器的数据类型和数据编码格式
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT --服务器资源的最后修改时间
Refresh: 1;url=http://www.it315.org ---定时刷新或每隔n秒跳转资源
Content-Disposition: attachment; filename=aaa.zip -- 以下载方式打开资源
Transfer-Encoding: chunked
Set-Cookie:SS=Q0=5Lb_nQ; path=/search -- 服务器发送给浏览器的cookie数据
Expires: -1 --通知浏览器不使用缓存
Cache-Control: no-cache
Pragma: no-cache
Connection: close/Keep-Alive 连接状态
Date: Tue, 11 Jul 2000 18:23:51 GMT 响应发出的时间
package cn.jxufe.c_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 使用HttpServletResponse修改响应数据 * response.setStatus(404) 设置状态码 * response.setHeader("name","value") 修改响应头 * response.getWriter().write() 以字符形式发送实体内容 * response.getOutputStream().write() 以字节形式发送实体内容 * */ public class ResponseDemo1 extends HttpServlet { // 1)tomcat服务器提供了一个HttpServletResponse对象,用于给开发者修改响应数据 // 2)通过service方法把response对象传入servlet中 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 3)通过response对象修改响应数据 /** * 修改响应 */ // 3.1 响应行 // 设置状态码 System.out.println("nihao"); response.setStatus(404); // response.sendError(404); // 404+404错误页面 // 3.2 响应头 response.setHeader("server", "webLogic"); // 3.3 实体内容(在浏览器主题部分看到的内容) // response.getWriter().write("this is content!"); 字符流 response.getOutputStream().write("this is content!!!".getBytes()); //字节流 } // 4)tomcat服务器把response对象转换成响应格式的字符串,发送给浏览器 }
package cn.jxufe.c_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 案例【location+302】请求重定向 */ public class ResponseDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 请求重定向( 跳转到其他页面 ) */ // //设置302状态码 // response.setStatus(302); // //设置location响应头 // response.setHeader("location", "/bbs/adv.html"); /** * 简化版本 */ response.sendRedirect("/bbs/adv.html"); } }
package cn.jxufe.c_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 案例【refresh】--定时刷新或每隔n秒跳转页面 */ public class ResponseDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 设置refresh响应头 // 设置秒数 // response.setHeader("refresh", "2"); // 每隔n秒跳转页面 response.getWriter().write("注册成功!3秒之后会跳转到主页"); // 设置refresh response.setHeader("refresh", "3;/bbs/adv.html"); } }
package cn.jxufe.c_servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 案例【content-type】--服务器发送给浏览器的数据类型和数据编码格式 */ public class ResponseDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置content-type响应 // response.setHeader("content-type", "text/html;charset=utf-8"); // response.setContentType("text/html;charset=utf-8");//等价于上面的代码 /** * 1)设置数据类型 */ // response.setContentType("text/html");//告诉浏览器以什么样的格式来解析实体内容 // response.setContentType("image/jpg");//告诉浏览器以什么样的格式来解析实体内容 /** * 注意: 一定要写服务器支持的数据类型,如果写了服务器不支持的类型,就会报错 */ /** * 2)设置数据编码格式 */ /** * 两个作用: * 1)设置输出数据的编码 * 2)告诉浏览器自动适应输出数据的编码 */ response.setContentType("text/html;charset=gbk"); // 和下面的代码是效果是一样的。 // response.setCharacterEncoding("utf-8"); //不会告诉浏览器自动跳转解码的码表 response.getWriter().write("<html><head><title>this is tille</title></head><body>主题</body></html>"); } }
package cn.jxufe.c_servlet; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ResponseDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { File file = new File("e:/mm.jpg"); /** * 告诉浏览器以下载的方法打开 */ response.setHeader("content-disposition", "attachment;filename=" + file.getName()); /** * 文件下载 */ // 1)读取本地文件 FileInputStream in = new FileInputStream(file); // 2)写出给浏览器(字节内容) OutputStream out = response.getOutputStream(); byte[] buf = new byte[1024]; int len = 0; // 边读边写 while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } // 关闭 in.close(); out.close(); } }