HTTP协议:
1、请求消息:客户端发送给服务器端的数据
数据格式:
1.请求行
2.请求头
3.请求空行
4.请求体
2、响应消息:服务器端发送给客户端的数据
数据格式:
1.响应行
1、组成:协议 / 版本 响应状态码 状态码描述
2、响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
状态码都是3位数字
分类:
1、1xx : 服务器接收客户端消息,但是没有接收完成,等待一段时间后,发送1xx状态码,“1开头的意思是...”
2、2xx : 成功。代表200
3、3xx : 重定向【资源跳转的一种方式】。
代表:302:
例如: 浏览器 --> 访问服务器资源A,A无法成功处理,返回给浏览器服务器资源C的地址,说:“我干不了,你让C去干吧~”,并给出本次响应状态位302。然后浏览器去找C
代表:304【访问缓存】:
例如:浏览器 --> 访问服务器资源a.png,因为图片这样的信息一般不会发生变化,浏览器的缓存中会保存这张图片a.png,如果第二次浏览器依然向服务器访问a.png,服务器会告诉浏览器说:“访问缓存吧”,并给出此次访问的状态码304。从而达到缓解服务器压力的目的
4、4xx : 客户端错误。
代表:404:
请求路径没有对应的资源
代表:405:
请求方式没有对应的 doGet 或者 doPost
5、5xx : 服务器错误,内部出现异常
代表:
500:服务器内部出现异常
2.响应头
1、格式:头名称 :值
2.常见的响应头:
1、Content - Type : 服务器告诉客户端本次响应体(HTML格式)数据格式以及编码格式
2、Content - disposition : 服务器告诉客户端以什么格式打开响应体数据
值:
in - line : 默认值,在当前页面内打开
attachment ; filename = xxx :以附件形式打开响应体。【文件下载】
3.响应空行
4.响应体
真实的,传输的数据
Response 对象
功能:设置响应消息
1. 设置响应行 :
1、格式:HTTP/1.1 200 ok
2、设置状态码:setStatus(int sc)
2.设置响应头 :
setHeader(String name, String value)
3.设置响应体 :
使用步骤:
1、获取输出流
字符输出流 : PrintWriter getWriter() 【打印流】
字节输出流 : ServletOutputStream getOutputStream() 【当作OutputStream使用】
2、使用输出流将数据输出到客户端浏览器
案例:
1.完成重定向
关键代码:
//1.设置状态码:302 response.setStatus(302); //2.设置响应头location response.setHeader("location","/day15/responseDemo2");
如果想要实现重定向的功能,设置状态码 和 设置响应头中的 location 都是固定的,只有 location 的值的有所变化的,因此以上代码可以被替换为:
response.sendRedirect("/day15/responseDemo2");
常见面试题:redirect 和 forward 的区别
重定向【redirect】的特点:
1.地址栏发生变化
2.重定向可以访问其他站点(其他服务器资源)
3.重定向是两次请求,不能使用 request 对象来共享数据
转发【forward】的特点:
1.转发地址栏路径不变
2.转发只能访问当前服务器下的资源
3.转发是一次请求
路径的写法:
1.路径分类:
1、相对路径 :通过相对路径不可以确定唯一资源
如:./index.html 【标识当前目录下】
不以斜杠开头,以 . 开头
规则:找到当前资源和目标资源之间的相对位置关系
./ : 标识当前目录,如果知识当前目录,那么 ./ 可以省略
../ : 标识上一级目录
2、【JSP常用】绝对路径:通过绝对路径可以确定唯一资源
如:http://localhost:8080/day15/responseDemo2 --> 绝对路径【省略协议、IP地址、端口号】:/day15/responseDemo2 ,以斜杠开头
规则:判断定义的路径是给 谁(浏览器 || 服务器) 用的?判断请求将来从哪发出
给浏览器用 :需要加 虚拟目录(项目的访问路径)【重定向√】
建议虚拟目录动态获取:request.getContextPath()
<a>、<form>、重定向
给服务器用: 不需要加 虚拟目录
转发路径
2.服务器输出字符数据到浏览器
步骤:
1、获取字符输出流
2、输出数据
乱码问题:
1.PrintWriter pw = response.getWriter(); 获取的流的默认编码是ISO-8859-1,即GBK
2.设置改流的默认编码
3.告诉浏览器响应体使用的编码
【注意:】在获取流之前设置编码:response.setContentType("text/html;charset=utf-8");
3.服务器输出字节数据到浏览器
4.验证码
@WebServlet("/checkCodeServlet") public class CheckCodeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width = 100; int height = 50; //1、创建一个对象,在内存中的图片 BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //2、美化图片 //2.1 填充背景色 Graphics graphics = image.getGraphics(); //获取画笔对象 //设置画笔颜色 graphics.setColor(Color.PINK); //填充方框背景色 graphics.fillRect(0,0,width,height); //2.2画边框 graphics.setColor(Color.BLUE); graphics.drawRect(0,0,width-1,height-1); String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); Character ch = null; //2.3写验证码 for (int i = 1; i <= 4; i++) { ch = str.charAt(random.nextInt(str.length())); graphics.drawString(ch+"",i*20,25); } //2.4画干扰线 graphics.setColor(Color.GREEN); graphics.drawLine(1,1,30,30); int x1,y1,x2,y2; for (int i = 1; i <= 10 ; i++) { x1 = random.nextInt(width); x2 = random.nextInt(width); y1 = random.nextInt(height); y2 = random.nextInt(height); graphics.drawLine(x1,y1,x2,y2); } //2.3写验证码 // graphics.drawString("A",20,25); // graphics.drawString("B",40,25); // graphics.drawString("C",60,25); // graphics.drawString("D",80,25); //3、将图片输出到页面上展示 ImageIO.write(image,"jpg",response.getOutputStream()); } }
<body> <img id="checkCode" onclick="changeImg()" src="/day15/checkCodeServlet"/> <br> <hr> <a href="">看不清?换一张</a> </body> <script> function changeImg(){ let checkCode = document.getElementById("checkCode"); let date = new Date().getTime();//欺骗服务器这是新的请求,否则会加载缓存中的验证码,验证码不会改变 checkCode.src = "/day15/checkCodeServlet?" + date; } </script>
ServletContext对象
1.概念:代表整个web应用,可以和程序的容器(服务器)来通信
2.获取:
1、通过request对象获取
request.getServletContext();
2、通过HttpServlet获取
this.getServletContext();
访问后控制台打印:
ServletContext对象代表整个Web应用,而改Web应用只有一份,因为:两种不同的方式访问到的对象均为同一个
3.功能:
1、获取 MIME 类型:
MIME 类型:在互联网通信过程中定义的一种文件数据类型
格式:大类型 / 小类型;
例如:text / html --> 标识这是一个纯文本的、html格式的文件
image / jpeg
获取:String getMimeType(String file)
控制台打印:
2、域对象 :共享数据
1.setAttribute(String name,Object value)
2.getAttribute(String name)
3.removeAttribute(String name)
注:ServletContext【谨慎使用】 对象范围:所有用户所有请求数据
先访问:/servletContextDemo3:doPost
在访问: /servletContextDemo4:doPost
控制台打印输出:
3、获取文件的真实路径(服务器的路径)
方法【重要】:String getRealPath(String path)
控制台打印:
案例:
文件下载需求:
1、页面显示超链接
2、点击超链接后弹出下载提示框
3、完成图片文件下载
分析:
1.超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能解析,则弹出下载提示框,不满足需求
2.任何资源都必须弹出下载提示框
3.使用响应头设置资源的打开方式:
content-disposit : attachment ; filename = xxx
步骤:
1.定义页面,编辑超链接 href 属性,指向Servlet,传递资源名称 filename
2.定义Servlet
1.获取文件名称
2.使用字节输入流加载文件进内存进内存
3.指定 response 的响应头
4.将数据写出到 response 输出流
问题:
中文文件名无法正常显示:
解决思路:
1.获取客户端使用的浏览器的版本信息
2.根据不同的版本信息,响应不同的数据,设置 filename 的编码方式不同
<body> <a href="/day15/img/natural_view.jpeg">图片</a> <hr/> <a href="/day15/img/video1.mp4">视频</a> <hr color="red"/> <a href="/day15/downloadServlet?filename=自然风景.jpeg">图片</a> <hr/> <a href="/day15/downloadServlet?filename=video1.mp4">视频</a> </body>
@WebServlet("/downloadServlet") public class DownloadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、获取请求参数,文件名称 String filename = request.getParameter("filename"); //2、使用字节输入流加载文件进内存 //2.1根据文件名找到文件的真实路径(即服务器路径) ServletContext servletContext = this.getServletContext(); String realPath = servletContext.getRealPath("/img/" + filename); //用字节流关联 FileInputStream fis = new FileInputStream(realPath); //解决中文文件名问题: //1、获取user-agent请求头 String agent = request.getHeader("user-agent"); //2、使用工具类方法编码文件名即可 filename = DownLoadUtils.getFileName(agent, filename); //3、设置response响应头 //3.1设置响应头类型:content-type String mimeType = servletContext.getMimeType(filename); response.setHeader("content-type",mimeType); //3.2设置响应头打开方式 response.setHeader("content-disposition","attachment;filename=" + filename); //4将输入流的数据写出到输出流中 ServletOutputStream outputStream = response.getOutputStream(); byte[] buff = new byte[1024 * 8]; int len = 0; while ((len = fis.read(buff)) != -1){ outputStream.write(buff,0,len); } } }
工具类:
//import sun.misc.BASE64Encoder; //导入BASE64Encoder报错的 import java.util.Base64; //导入此包,【从网上查资料说是JDK版本不一致,JDK9之后更新为此包,】 import java.io.UnsupportedEncodingException; import java.net.URLEncoder; public class DownLoadUtils { public static String getFileName(String agent, String filename) throws UnsupportedEncodingException { if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); } else if (agent.contains("Firefox")) { // 火狐浏览器 //BASE64Encoder base64Encoder = new BASE64Encoder(); Base64.Encoder base64 = Base64.getEncoder(); filename = "=?utf-8?B?" + base64.encode(filename.getBytes("utf-8")) + "?="; } else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); } return filename; } }
标签:浏览器,String,--,filename,day14,响应,服务器,HTTP,response From: https://www.cnblogs.com/yumengqifei/p/16871764.html