Request&Response
2022-11-17 本文已影响0人
h2coder
概述
-
JavaWeb中,服务端要接受到请求,需要使用Request对象,做出响应需要使用Response对象
-
请求
- 浏览器发送HTTP请求到Web服务器(Tomcat)
- HTTP请求中包含请求行、请求头、请求体
- Tomcat会对HTTP请求数据进行解析,并将解析结果转化为一个Request对象
- 我们通过Servlet的service方法,获取到Request对象,就可以通过Request对象获取请求参数
-
响应
- 业务处理完毕后,我们通过Servlet的service方法中传入的Response对象,对请求做出下响应
- Tomcat就会将Resonse对象转化为HTTP响应数据,HTTP响应数据包含响应行、响应头、响应体,发送给浏览器
- 浏览器解析响应结果,最终显示给用户
Request对象
Request对象,用来封装请求数据的对象
Request的继承关系
- ServletRequest(根接口)
- HttpServletRequest(针对HTTP协议封装的请求对象接口)
- RequestFacade(Web服务器对Request对象的实现,例如这个Tomcat实现的)
Request获取数据
@WebServlet(value = "/req03")
public class Demo3Servlet extends HttpServlet {
private static final long serialVersionUID = -556975635735989032L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
获取请求行数据
请求行,包含请求方式、请求资源路径、HTTP协议以及版本号
1628748240075.png- 获取请求方式
request.getMethod();
- 获取虚拟目录(项目访问路径)
/request-demo
request.getContextPath();
- 获取URL(统一资源定位符)
/request-demo/req03
request.getRequestURI();
- 获取URL(统一资源标识符)
http://localhost:8080/request-demo/req03
request.getRequestURL();
- 获取请求参数(GET请求方法)
username=admin&password=123&hobby=1&hobby=2
request.getQueryString();
获取请求头数据
1628768652535.png//请求头数据:
//Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
//Accept-Encoding: gzip, deflate, br
//Accept-Language: zh-CN,zh;q=0.9
//User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53
System.out.println("浏览器支持的资源类型 Accept = " + req.getHeader("accept"));
System.out.println("浏览器的版本 User-Agent = " + req.getHeader("user-agent"));
获取请求体数据
1628768665185.png- 获取字节输入流,如果浏览器发送的是字节数据,例如文件数据,就使用该方法
ServletInputStream inputStream = request.getInputStream();
- 获取字符输入流,如果浏览器发送的是文本,就使用该方法
BufferedReader reader = request.getReader();
获取请求参数的通用方式
GET请求的请求参数在请求行中,拼接在资源路径中。POST请求的请求参数在请求体中。那么获取请求参数的方式就不同。
- GET请求
String params = request.getQueryString()
- POST请求
BufferedReader reader = request.getReader();
那么针对不同的请求方式,需要区分编写,实在太麻烦了,所以Request对象提供了3种获取方法。
- 获取所有请求参数Map集合
Map<String, String[]> parameterMap = request.getParameterMap();
- 根据名称,获取对应的参数值数组(数组)
String[] hobbys = getParameterValues("hobby");
- 根据名称,获取对应的值(单个值)
String username = request.getParameter("username");
请求参数中文乱码问题
如果是POST请求,请求参数中存在中文,获取时,就会乱码。
1628829610823.png原因:
-
POST请求在获取参数时,调用的是Request的getReader()
-
Tomcat在获取流时,采用的编码是
ISO-8859-1
,而浏览器发送的参数使用的是UTF-8
进行编码的 -
该编码不支持中文,所以会出现乱码
-
解决方案
- Tomcat在获取流之前,设置编码为
UTF-8
- 通过Request对象,setCharacterEncoding("UTF-8")设置编码
- Tomcat在获取流之前,设置编码为
@WebServlet(value = "/req03")
public class Demo3Servlet extends HttpServlet {
private static final long serialVersionUID = -556975635735989032L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Tomcat 8.0 后,GET请求中文已经处理了中文乱码问题,但POST没有处理
//重点:POST请求的参数放在请求体中,默认编码是ISO-8859-1,而不是UTF-8,中文就会乱码,所以需要重新指定
request.setCharacterEncoding("UTF-8");
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
System.out.println("key = " + entry.getKey() + "," + "value = " + Arrays.toString(entry.getValue()));
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Request请求转发
请求转发,是一种在服务器内部的资源跳转方式
1628851404283.png- 场景流程
- 浏览器发送请求给服务器,获取资源A
- 资源A,只能完成一部分功能,需要继续交给资源B进行处理,就需要转发
- 资源B,完成剩下的功能后,将结果返回给浏览器
- 资源A到资源B的过程,就叫请求转发
request.getRequestDispatcher(path).forward(request, response);
- 资源转发的过程中,可以通过Request对象设置参数,进行通信
//存数据到Request域
request.setAttribute("name", "zhang san");
//从Request域中获取数据
Object attribute = request.getAttribute("name");
//从Request域中删除数据
request.removeAttribute("name");
示例代码
- 资源A
/**
* 转发前的资源
*/
@WebServlet(value = "/a")
public class Demo4Servlet extends HttpServlet {
private static final long serialVersionUID = 5039248570478620151L;
public static final String KEY_NAME = "name";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决POST请求参数中文乱码问题
request.setCharacterEncoding("UTF-8");
//请求转发的特点:
//1、转发后,地址栏的URL地址不变
//2、转发只有一次请求
//3、只能转发给当前服务器的内部的资源,不能请求外部的!
System.out.println("---------------- demo4 servlet,发起请求转发 ----------------");
//跳转的路径
String path = "b";
//存数据
request.setAttribute(KEY_NAME, "zhang san");
System.out.println("demo4 servlet 存数据到request中...");
request.getRequestDispatcher(path).forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 资源B
/**
* 跳转后的资源
*/
@WebServlet(value = "/b")
public class Demo5Servlet extends HttpServlet {
private static final long serialVersionUID = 7691480142539364773L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("---------------- demo5 servlet,收到请求 ----------------");
System.out.println("b 资源");
//获取传递的数据
Object attribute = request.getAttribute(Demo4Servlet.KEY_NAME);
System.out.println("demo5 servlet 获取到的数据:" + attribute);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
请求转发的特点
- 转发后,地址栏的URL地址不变
- 转发只有一次请求
- 只能转发给当前服务器的内部的资源,不能请求外部的!
Response对象
Response对象,用来封装响应数据的对象
Response继承体系
- ServletResponse(根接口)
- HttpServletResponse(对HTTP协议进行封装的子接口)
- ResponseFacade(Tomcat中定义的实现类)
Response响应数据
HTTP响应数据,包括三大内容,分别是响应行、响应头、响应体
设置响应行
响应行,也有三部分组成,分别是HTTP协议及其版本号、响应状态码、响应状态码的描述,对于响应行的设置,我们一般只设置响应码即可,其他的将有Tomcat帮我们自动填充上
1628858926498.png//状态码 200 代表请求成功
response.setStatus(200);
设置响应头
响应头和请求头一样,都是由key-value键值对构成
1628859051368.png//Content-Type响应头,代表本次请求响应的数据类型,text/html代表HTML类型的文本数据
response.setHeader("Content-Type", "text/html");
设置响应体
响应体分为字节数据和字符数据,分别对应2个方法
1628859268095.png- 响应字节数据
ServletOutputStream out = response.getOutputStream();
- 响应字符数据
PrintWriter writer = response.getWriter();
Response响应中文乱码问题
想写出字符输出到响应体,返回给浏览器显示时,如果字符数据中存在中文,则会出现乱码
1628846824194.png原因:
- Tomcat获取字符输出流时,使用的是ISO-8859-1字符集
- 浏览器解码字符数据使用的字符集是UTF-8,2端编码不一致,导致乱码
解决方案
- 设置响应字符流的编码为UTF-8
response.setContentType("text/html;charset=utf-8");
Response重定向
重定向,是一种资源跳转方式,需要服务端和客户端进行配合
1628859860279.png场景流程
- 浏览器发送请求给服务器,服务器资源A接受到请求
- 资源C发现无法处理,就会给浏览器一个302响应状态码,并添加一个location响应头,设置上浏览器资源B的路径
- 浏览器接收到响应码为302,就会寻找location响应头,请求这个location响应头对应的资源地址
- 资源D接收到请求后,响应结果给浏览器,这个过程就叫重定向
实现重定向
- 实现重定向有2种方式:
//方式一:设置302状态码,以及响应头location,设置目标地址
response.setStatus(302);
response.setHeader("location", url);
//方式二:使用sendRedirect()方法(推荐这种)
response.sendRedirect(url);
示例代码
- 资源C
/**
* 跳转前
*/
@WebServlet(value = "/c")
public class Demo7Servlet extends HttpServlet {
private static final long serialVersionUID = 419981648051969464L;
public static final String KEY_NAME = "name";
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("资源 c");
//重定向的特点:
//1、浏览器的地址栏地址改变为重定向的地址
//2、会发起2次请求
//3、3次请求之间,不能数据共享
//存储数据到request
request.setAttribute(KEY_NAME, "zhang san");
//发起重定向
String url = "d";
//方式一:设置302状态码,以及响应头location,设置目标地址
//response.setStatus(302);
//response.setHeader("location", url);
//方式二:使用sendRedirect()方法(推荐这种)
response.sendRedirect(url);
//可以重定向到服务器外的资源
//response.sendRedirect("http://www.baidu.com");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 资源D
/**
* 跳转后
*/
@WebServlet(value = "/d")
public class Demo8Servlet extends HttpServlet {
private static final long serialVersionUID = 3830075411283682097L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("资源 d");
Object attribute = request.getAttribute(Demo7Servlet.KEY_NAME);
System.out.println("获取数据:" + attribute);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
重定向的特点
- 浏览器的地址栏地址改变为重定向的地址
- 浏览器会发起2次请求
- 3次请求之间,不能数据共享
请求转发和重定向对比
1628862652700.png 1628862170296.pngResponse响应字节数据
//获取响应体输出流
ServletOutputStream out = response.getOutputStream();
//读取文件
FileInputStream fis = new FileInputStream("C:\\Develop\\Code\\Java\\java_up_181\\day24-request-response\\src\\main\\webapp\\imgs\\Desert.jpg");
//写字节数据到响应体中
byte[] buf = new byte[1024 * 8];
int len;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
Response响应字符数据
//获取响应体字符输出流
PrintWriter writer = response.getWriter();
//写出字符数据到响应体
writer.write("<h1>哈哈哈哈</h1>");
writer.flush();