HTTP-复习
概述
- Hyper Text Transfer Protocol 超文本传输协议
- 传输协议:定义了客户端和服务器通信时,发送数据的格式
- 特点:
- 基于TCP/IP的高级协议
- 默认端口号:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
- 历史版本:
- 1.0:每次请求响应都会建立连接
- 1.1:复用连接
请求
请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
- 请求方式:
- HTTP协议有7种请求方式,常用的有2种
- GET:
- 请求参数在请求行中,在url后
- 请求的url长度有限制
- 不太安全
- POST:
- 请求参数在请求体中
- 请求长度无限制
- 相对安全
- GET:
- HTTP协议有7种请求方式,常用的有2种
- 请求方式:
请求头-客户端浏览器告诉服务器一些信息
请求头名称:请求头值
Host:localhost
- 常见请求头:
- User-Agent:浏览器告诉服务器,访问时使用的浏览器版本信息(可以在服务器获取该头信息,解决浏览器的兼容性问题)
- Referer:http://localhost/login.html(告诉服务器,当前请求从哪里来)
- 作用:
- 防盗链
- 统计工作
- 作用:
- 常见请求头:
请求空行
空行
请求体(正文)
- 封装POST请求消息的请求参数的
## Request
Request-原理
- tomcat服务器会根据请求url中的资源路径,创建对应的ServletDemo的对象
- tomcat服务器,会创建request和response对象,request对象中封装请求消息数据
- tomcat将request和response两个对象传递给service方法,并且调用service方法
- 程序员可以通过request获取请求消息数据,通过response对象设置响应消息数据
- 服务器在给浏览器做出响应前,会从response对象中获取响应消息数据
- request和response对象是由服务器创建的,我们来使用它们
- request对象是来获取请求消息,response对象是来设置响应消息的
Request-对象继承体系结构
- ServletRequest -- 接口
- HttpServletRequest(继承ServletRequest) -- 接口
- org.apache.catalina.connector.RequestFacade(实现HttpServletRequest)
Request-获取请求消息
获取请求消息数据
- 获取请求行数据
- 方法:
- 获取请求方式:String getMethod()
- 获取虚拟目录:String getContextPath()
- 获取Servlet路径:String getServletPath()
- 获取get方式请求参数:String getQueryString()
- 获取请求URI:String getRequestURI() :/xxx/aaa
- StringBuffer getRequestURL():http://localhost/xxx/aaa
- 获取协议及版本:String getProtocol()
- 获取客户机的IP地址:String getRemoteAddr()
- 方法:
- 获取请求头数据
- 方法:
- 通过请求头名称获取请求头的值:String getHeader(String name)
- 获取所有的请求头名称:Enumeration< String > getHeaderName()
- 方法:
- 获取请求体数据
- 请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
- 步骤:
- 获取流数据
- 获取字符输入流,只能操作字符数据:BufferedReader getReader()
- 获取字节输入流,可以操作所有类型数据:ServletInputStream getInputStream()
- 再从流对象中获取数据
- 获取流数据
- 获取请求行数据
其它功能
获取请求参数(通用方式):get、post都可用
- 根据参数名称获取参数值:String getParameter(String name)
- 根据参数名称获取参数值的数组:String[] getParameterValues(String name)
- 获取所有请求的参数名称:Enumeration< String > getParameterNames()
- 获取所有参数的map集合:Map< String,String[] > getParameterMap()
中文乱码问题:
get方式:tomcat 8 已经将get方式乱码问题解决了
post方式:会乱码
解决:req.setCharacterEncoding("utf-8");
请求转发:一种在服务器内部的资源跳转方式
- 步骤
- 通过req对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:forward(ServletRequest request,ServletResponse response)
- 特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求
- 步骤
共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
- 存储数据:setAttribute(String name,Object obj)
- 通过键获取值:Object getAttribute(String name)
- 通过键移除键值对:removeAttribute(String name)
获取ServletContext
- ServletContext getServletContext()
响应
- 响应行
- 组成:协议/版本 响应状态码 状态码描述
HTTP/1.1 200 OK
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
- 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码
- 2xx:成功
- 3xx:重定向-302(重定向),304(访问缓存)
- 4xx:客户端错误-404(路径没有对应资源),405(请求方式没有对应的方法)
- 5xx:服务器端错误-500(服务器内部出现异常)
- 组成:协议/版本 响应状态码 状态码描述
- 响应头
- 格式:头名称:值
- 常见的响应头:
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- 值:
- in-line:默认值,在当前页面内打开
- attachment;filename=xxx:以附件形式打开响应体,文件下载
- 值:
- 响应空行
- 响应体:传输的数据
Response
功能:设置响应消息
- 设置响应行
- 格式:HTTP/1.1 200 ok
- 设置状态码:setStatus(int sc)
- 设置响应头:setHeader(String name,String value)
- 设置响应体
- 使用步骤:
- 获取输出流
- 字符输出流:PrintWriter getWriter()
- 字节输出流:ServletOutputStream getOutputStream()
- 使用输出流,将数据输出到客户端浏览器
- 获取输出流
- 使用步骤:
案例
完成重定向
- 资源跳转的方式
1 | /** |
- 重定向的特点
- 地址栏发生变化
- 重定向可以访问其它站点(服务器)资源
- 重定向是两次请求
- 路径写法
- 路径分类
- 相对路径:通过相对路径不可以确定唯一资源(./xxx/aaa,以.开头的路径)
- 绝对路径:通过绝对路径可确定唯一资源(/xxx/aaa,以/开头的路径)
- 规则:判断定义的路径是给谁用的?(请求从哪里发出)如果是给客户端浏览器使用,需要加虚拟目录(项目的访问路径),如果是给服务器使用则不需要加虚拟目录
- 动态获取虚拟目录:request.getContextPath()
- 路径分类
服务器输出字符数据到浏览器
1 |
|
服务器输出字节数据到浏览器
1 |
|
验证码
- 本质上是一张图片
- 目的:防止恶意表单
ServletContext对象
概念:代表整个Web应用,可以和程序的容器(服务器)通信
获取:
- 通过request对象获取request.getServletContext();
- 通过HttpServlet获取this.getServletContext();
功能:
获取MIME类型
- MIME类型:在互联网通信过程中定义的一种文件数据类型
- 格式: 大类型/小类型 text/html, image/jpeg
- 获取:String getMimeType(String file)
- MIME类型:在互联网通信过程中定义的一种文件数据类型
域对象:共享数据
- setAttribute(String name,Object value)
- getAttribute(String name)
- removeAttribute(string name)
ServletContext对象范围:所有用户所有请求的数据
获取文件的真实(服务器)路径
- 方法:String getRealPath(String path)
1
2
3
4
5
6
7
8// web目录下资源访问
ServletContext context = this.getServletContext();
String realPath = context.getRealPath("/b.txt");
// WEB-INF目录下资源访问
String realPath1 = context.getRealPath("/WEB-INF/c.txt");
// src目录下资源访问
String realPath2 = context.getRealPath("/WEB-INF/classes/a.txt");
案例
文件下载
步骤
- 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
- 定义Servlet
- 获取文件名称
- 使用字节输入流加载文件进内存
- 指定response的响应头:
content-disposition:attachment;filename=xxx
- 将数据写到response输出流
1
<a href="/path/downloadServlet?filename=1.jpg">下载</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String filename = req.getParameter("filename");
ServletContext context = this.getServletContext();
String realPath = context.getRealPath("/img/"+filename);
FileInputStream fis = new FileInputStream(realPath);
String mimeType = context.getMimeType(filename);
resp.setHeader("content-type",mimeType);
String agent = req.getHeader("user-agent");
filename = DownloadUtil.getFileName(agent, filename);
System.out.println(agent);
System.out.println(filename);
resp.setHeader("content-disposition","attachment;filename="+filename);
ServletOutputStream sos = resp.getOutputStream();
byte[] buff = new byte[1024*8];
int len = 0;
while((len=fis.read(buff))!=-1){
sos.write(buff,0,len);
}
fis.close();
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}中文文件名问题
- 解决思路:
- 获取客户端使用的浏览器使用版本信息
- 根据不同的版本信息,设置filename的编码方式不同
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class DownloadUtil {
public static String getFileName(String agent,String filename) throws UnsupportedEncodingException {
if(agent.contains("MSIE")){
filename = URLEncoder.encode(filename,"utf-8");
filename = filename.replace("+"," ");
}else if(agent.contains("Firefox")){
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
}else{
filename = URLEncoder.encode(filename,"utf-8");
}
return filename;
}
}- 解决思路: