请求与响应
1. 请求-响应概述
HTTP 协议通过请求消息与响应消息进行通信,分别对应 Request 对象和 Response 对象。
Request 对象和 Response 对象的原理:
Request 和 Response 对象是由服务器创建的,我们只是使用它们;
Request 对象是来获取请求消息的,Response 对象是来设置响应消息的。
在接触了 Request 和 Response 之后,我们再来看 Tomcat 运行 Servlet 的原理:
Tomcat 服务器会根据请求 url 中的资源路径,创建对应的 Servlet 实现类的对象;
Tomcat 服务器会创建 Request 和 Response 对象,其中 Request 对象中封装请求消息数据;
Tomcat 将 Request 和 Response 两个对象传递给 Servlet 对象的
service
方法,并调用service
方法;程序员可以通过 Request 对象获取请求消息数据,可以通过 Response 对象设置响应消息数据;
服务器在给浏览器做出响应之前,会从 Response 对象中取出程序员设置的响应消息数据,然后发送“响应消息”给客户端浏览器。
2. 请求 Request
前要知识——URL 及 URI 的定义:
- URL:统一资源定位符,如 http://localhost/myTomcat/demo2
- URI:统一资源标识符,如 /myTomcat/demo2
- 区别:URI 的范围 > URL 的范围,好比 “共和国 > 中国人民共和国”
2.1 Request 的继承体系结构
API | 类型 |
---|---|
ServletRequest | 接口 |
HttpServletRequest | 接口(继承上述接口) |
org.apache.catalina.connector.RequestFacade | 类(实现上述接口,tomcat 提供) |
2.2 Request 对象的功能
2.2.1 获取请求消息数据
如非说明,重点掌握 * 标注内容。
获取请求行数据——以
GET /myTomcat/demo2?username=zhangsan HTTP/1.1
为示例具体获取内容 对应的示例 调用方法 请求方式 GET String getMethod()
(*)虚拟目录 /myTomcat String getContextPath()
Servlet 路径 /demo2 String getServletPath()
get 方式请求参数 name=zhangsan String getQueryString()
(*)请求 URI /myTomcat/demo2 String getRequestURI()
请求 URL http://localhost/myTomcat/demo2 StringBuffer getRequestURL()
协议及版本 HTTP/1.1 String getProtocol()
客户机的 IP 地址 String getRemoteAddr()
获取请求头数据
具体获取内容 调用方法 (*)通过请求头的名称获取请求头的值 String getHeader(String name)
获取所有的请求头名称 Enumeration<String> getHeaderNames()
获取请求体数据:先获取流对象,然后从流对象中拿数据。
方法 说明 BufferedReader getReader()
获取字符输入流,只能操作字符数据 ServletInputStream getInputStream()
获取字节输入流,可以操作所有类型数据 获取请求参数的通用方式(兼容 GET 与 POST):
都很重要,掌握。
方法 作用 String getParameter(String name)
根据参数名称获取参数值 String[] getParameterValues(String name)
根据参数名称获取参数值的数组 Enumeration<String> getParameterNames()
获取所有请求的参数名称 Map<String, String[]> getParameterMap()
获取所有参数的 map 集合
2.2.2 请求转发
请求转发:一种在服务器内部的资源跳转方式(AServlet -> Bservlet)。
转发的步骤:
- 通过 Request 对象获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
。 - 使用 RequestDispatcher 对象来进行转发:
forward(ServletRequest request, ServletResponse response)
。
转发的特点:
- 转发前后浏览器地址栏路径不发生变化;
- 只能转发到当前服务器内部的资源中;
- 转发和原来的 Servlet 属于同一次请求。
2.2.3 共享数据
先要知识:域对象表示一个有作用范围的对象,可以在范围内共享数据;
request 域:代表一次请求的范围,一般用于在请求转发的多个资源中共享数据。
Request 对象共享数据的方法:
方法 | 说明 |
---|---|
void setAttribute(String name, Object obj) | 存储数据到 request 域中 |
Object getAttribute(String name) | 通过键获取值 |
void removeAttribute(String name) | 通过键移除键值对 |
2.2.4 获取 ServletContext 对象
详情见 ServletContext 相关内容。
获取 ServletContext 对象:ServletContext getServletContext()
。
2.3 案例巩固
见 https://www.bilibili.com/video/BV1uJ411k7wy?p=709 。
3. 响应 Response
Response 对象的功能为设置响应消息。其使用比 Request 相对简单。
3.1 设置响应消息数据
设置响应行
- 格式:
HTTP/1.1 200 ok
- 设置状态码:
setStatus(int sc)
- 格式:
设置响应头:
setHeader(String name, String value)
设置响应体:需要先获取输出流,然后使用输出流将数据输出到客户端浏览器。
字符输出流:
PrintWriter getWriter()
获取流对象后通常使用
write
方法写数据,不需要刷新流通常获取流对象之前,还需要将编码规则设置好
// 设置流的编码为 UTF-8(默认为 ISO-8859-1) // 实际上直接使用第二或三行代码即可,不需要本条设置 response.setCharacterEncoding("utf-8"); // 告诉客户端浏览器,(我)服务器发送的消息体数据的编码,以此告诉浏览器需要使用该编码进行解码 response.setHeader("content-type", "text/html;charset=utf-8"); // 第二行代码的简化版 response.setContentType("text/html;charset=utf-8")
字节输出流:
ServletOutputStream getOutputStream()
// 同字符输出流,也需设置编码 response.setContentType("text/html;charset=utf-8");
3.2 重定向
自己实现(原理细节版):// 1. 告诉浏览器重定向:状态码 302 response.setStatus(302); // 2. 告诉浏览器新资源的路径:响应头 location: 新资源的路径 response.setHeader("location", "/day15/responseDemo2");
或调用现成的方法:
response.sendRedirect("/day15/responseDemo2");
注意,对于上面的虚拟目录
/day15
,通常我们在实际工程中不这么写,因为虚拟目录有可能在生产中发生变化,为防止强耦合我们通常使用request.getContextPath()
来获取虚拟目录,将上述的新资源路径写作request.getContextPath()+responsetDemo2
。
重定向的特点:
- 重定向的地址栏发生变化;
- 重定向可以访问其他站点(服务器)的资源,如
response.sendRedirect("www.itcast.cn");
; - 一次重定向对应两次请求(也就意味着有两个 request 域,故不能使用 request 对象来共享数据)。
3.3 路径的写法
在 HTML/JSP 页面中推荐使用绝对路径。
绝对路径:通常以斜杠
/
开头。如 http://localhost/day15/responseDemo1上述通常简化为:
/day15/responseDemo1
相对路径:根据当前资源和目标资源之间的相对位置关系确定资源,以点
.
开头。如./target.html
一个点时也可简化为
target.html