Request(请求)和Response(响应)

  • Request:获取请求数据
  • Response:设置响应数据

Request

Request继承体系

image-20221107160322199

  1. Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法中
  2. 使用request对象,查阅JavaEE API文档的HttpServletRequest接口

Request获取请求数据

  1. 请求行: GET /request-demo/req1?username=zhangsan HTTP/1.1
    • String getMethod():获取请求方式:GET
    • String getContextPath():获取虚拟目录(项目访问路径):/request-demo
    • StringBuffer getRequestURLO:获取URL(统一资源定位符): http://localhost:8080/request-demo/req1
    • String getRequestURI():获取URI(统一资源标识符):/request-demo/req1
    • String getQueryString():获取请求参数(GET方式):username=zhangsan&password=123
  2. 请求头:User-Agent: Mozilla/5.0 Chrome/91.0.4472.106
    • String getHeader(String name):根据请求头名称,获取值
  3. 请求体:username=superbaby&password=123
    • ServletInputStream getlnputStream():获取字节输入流
    • BufferedReader getReader():获取字符输入流
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
34
35
36
37
38
39
40
41
42
43
44
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


// 请求行部分
// 获取请求方式:GET
String method = req.getMethod();

// 获取虚拟目录
String contextPath = req.getContextPath();

// 获取URL
StringBuffer url = req.getRequestURL();

// 获取URI
String uri = req.getRequestURI();

// 获取请求参数
String queryString = req.getQueryString();


//--------请求头部分
// 获取请求头:user-agent:浏览器版本信息
String header = req.getHeader("user-agent");


System.out.println(method);
System.out.println(contextPath);
System.out.println(url);
System.out.println(uri);
System.out.println(queryString);
System.out.println(header);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求体:
// 获取字符输入流:
BufferedReader br = req.getReader();

// 读取数据
String line = br.readLine();
System.out.println(line);
}

image-20221107162825291

Request通用方式获取请求参数

  • MapgetParameterMap():获取所有参数Map集合
  • String[] getParameterValues(String name)∶根据名称获取参数值(数组)
  • String getParameter(String name):根据名称获取参数值(单个值)
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
34
35
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 获取Map集合
Map<String, String[]> map = req.getParameterMap();
for(String key : map.keySet()) {
System.out.print(key+": ");
String[] values = map.get(key);
for(String val : values){
System.out.print(val + " ");
}
System.out.println("");
}
System.out.println("===============");

// 更具key获取参数
String[] hobbies = req.getParameterValues("hobby");
for(String hobby : hobbies) {
System.out.print(hobby + " ");
}
System.out.println("");
System.out.println("===============");


// 获取单个值
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}

解决中文乱码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// post解决:设置字符输入流编码
req.setCharacterEncoding("UTF-8");


// get方式因为浏览器编码方式是UTF-8而tomcat解码方式是ISO-8859-1,导致乱码

// 1.url编码
String encode = URLEncoder.encode(username, "utf-8");

// 2.url解码
String decode = URLDecoder.decode(encode, "utf-8");

// 3.转化为字节数据
byte[] bytes = decode.get("ISO-8859-1");

// 4.将字节数据转化成字符串
String s = new String(bytes, "utf-8");


// get解决:
String username = req.getParameter("username");
username = new String(username.get(StandarCharsets.ISO_8859_1), StanderCharsets.UTF_8);

image-20221107172108277

Request请求转发

  • 请求转发(forward):一种在服务器内部的资源跳转方式。
  • 实现方式:req.getRequestDispatcher(“资源B路径”).forward(req,resp);
  • 请求转发资源间共享数据:使用Request对象
    • void setAttribute(String name, Object o):存储数据到request域中
    • Object getAttribute(String name):根据key,获取值
    • void removeAttribute(String name):根据key,删除该键值对
  • 请求转发特点:
    • 浏览器地址栏路径不发生变化
    • 只能转发到当前服务器的内部资源
    • 一次请求,可以在转发的资源间使用request共享数据

Response

Response设置响应数据功能介绍

响应数据分为3部分:

  1. 响应行:HTTP/1.1 200 OK
    void setStatus(int sc)∶设置响应状态码

  2. 响应头: Content-Type: text/html
    void setHeader(String name, String value)∶设置响应头键值对

  3. 响应体:

    1
    <html><head></head><body></body></html>

    PrintWriter getWriter():获取字符输出流
    ServletOutputStream getOutputStream():获取字节输出流

Response重定向

重定向是一种资源跳转的方式,与转发有很大的区别

重定向流程:浏览器请求资源A,资源A响应(我处理不了,找别人处理《状态码:302 》,那个人的位置是xx)然后浏览器自动请求资源B

转发:浏览器请求资源A,资源处理数据资源将数据转发给资源B

1
2
3
4
5
6
7
8
 // 重定向
// // 设置响应状态码302
// response.setStatus(302);
// // 设置响应头
// response.setHeader("Location", "/servlet_demo1_war/resp2");

// 简化方式完成重定向
response.sendRedirect("/servlet_demo1_war/resp2");

重定向特点:

  • 浏览器地址栏路径发生变化
  • 可以重定向到任意位置的资源(服务器内部、外部均可)
  • 两次请求,不能在多个资源使用request共享数据

重定向与转发比较

  • 请求转发:客户浏览器发送http请求,web服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。
  • 重定向过程:客户浏览器发送http请求,web服务器接受后发送302状态码响应及对应新的location给客户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址,服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
区别 重定向 请求转发
在哪里完成 客户端完成(可以在不同的服务器下完成) 服务器端完成(必须是在同一台服务器下完成)
浏览器发送请求的次数 2次或者2次以上 1次
地址栏URL是否发生改变 地址栏发生变化 地址栏的地址不变
是否共享request 不共享数据(经过重定向后,request内的对象将无法使用) 共享数据(以前的request中存放的变量不会失效,就像把两个页面拼到了一起)
第二次请求发起者 浏览器 服务器
第二次的请求路径方式 绝对路径 相对路径
速度 因为还要浏览器发送第二次请求,重定向相对慢一点
语句 response.sendRedirect(“success.jsp”); request.getRequestDispatcher(“success.jsp”).forward(request,response);

image-20221107194350119

Response响应字符

1
2
3
4
5
6
7
8
9
response.setContentType("text/html;charset=utf-8");
// 1.获取字符串输出流
PrintWriter writer = response.getWriter();

// content-type,设置头
// response.setHeader("content-type", "text/html");

writer.write("张三");
writer.write("<h1>aaa</h1>");

Response响应字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 // 1.读取文件
FileInputStream fis = new FileInputStream("C://Users//jpc//Desktop//OldDesktop//5.jpg");

// 2.获取response字节输出流
ServletOutputStream os = response.getOutputStream();

// 3.完成流的copy
// byte[] buff = new byte[1024];
// int len = 0;
// while((len = fis.read(buff)) != -1) {
// os.write(buff, 0, len);
// }
IOUtils.copy(fis, os);

fis.close();