Request & Response

Request

  • Request 获取请求数据

Request 继承体系

  • Tomcat 需要解析浏览器请求, 封装为 request 对象,并且创建 request 对象传到 sevice 方法中

  • 当我们的Servlet类实现的是Servlet接口的时候,service方法中的参数是ServletRequest和ServletResponse

  • 当我们的Servlet类继承的是HttpServlet类的时候,doGet和doPost方法中的参数就变成HttpServletRequest和HttpServletReponse

    Request继承图

Request 获取请求数据

  1. 请求行

    请求行

    • String getMethod() : 获取请求方式 GET
    • String getContextPath() : 获取虚拟目录(项目访问路径)/request-demo
    • StringBuffer getRequestURL() : 获取统一资源定位符 http://localhost:8080/request-demo/req1
    • String getRequestURI() : 获取 URI (统一资源标识符) request-demo/req1
    • String getQueryString() : 获取请求参数(GET 方式)username=zhangsan
  2. 请求头

    • String getHeader(name: String) : 根据请求头名称获取值
  3. 请求体 (POST)

    • ServletInputStream getInputStream() 获取请求体字节输入流
    • BufferedReader getReader() : 获取请求体字符输入流

    获取的流不用手动关闭,随 request 对象销毁而自动关闭

统一获取请求参数

由于 GET 方式的请求参数在请求头中, POST 方式的请求参数在请求体中,上述方法获取请求参数对应的方法不同,而使用 request 的以下方法可以统一获取请求参数

  • Map<String, String[]> getParameterMap() 获取所有参数 Map 集合

  • String[] getParameterValues(String var1) 根据参数名称获取参数值(数组)

  • String getParameter(String var1) 根据参数名称获取单个参数值

处理中文请求参数乱码

  • 由于浏览器 URL 编码使用 UTF-8 格式编码,而 tomcat7 以及之前的版本解码 URL 使用 ISO-8859-1 解码,在请求中含有中文字符时会出现乱码
  • tomcat8.0 及以后使用 UTF-8 格式解码,无需处理乱码

URL 编码

  1. URL 编码会将字符转换为可通过因特网传输的格式。

  2. URL 只能使用 ASCII 字符集来通过因特网进行发送。

  3. 对于非 ASCII 字符,将字符按照编码格式转为二进制,在每个字节转成两个16进制数并在前面加%

image-20230317133545142

http://localhost/webDemo/?username=%E5%BC%A0%E4%B8%89

  1. URL 不能包含空格。URL 编码通常使用 + 来替换空格。

POST 处理乱码

在获取参数前设置字符输入流编码

1
request.setCharacterEncoding("UTF-8");

GET 处理乱码

  • 由于 GET 方式获取请求不使用字符输入流,上述设置无法解决 GET 参数乱码问题
1
2
3
4
5
6
7
8
9
10
//假设 s 为 编码的 URL %E5%BC%A0%E4%B8%89
String s = URLEncoder.encode("张三", "utf-8");
// s1 为 tomcat 解码后的 URL å¼ ä¸
String s1 = URLDecoder.decode(s, "iso-8859-1");
//方式1 先以 iso-8859-1 格式编码,再以 utf-8 格式解码
String s2 = URLEncoder.encode(s1, "iso-8859-1");
String s3 = URLDecoder.decode(s2, "utf-8");//张三
//方式2 先以 iso-8859-1 格式转为字节数组,再以 utf-8 格式转为字符串
byte[] bytes = s1.getBytes("iso-8859-1");
String s4 = new String(bytes, "utf-8");//张三

一句代码解决 ( GET POST 均可使用)

1
2
3
String username = new String(
request.getParameter("username").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8
);

Request 请求转发

  • 请求转发:一种在服务器内部的资源跳转方式

  • 实现方式

    需求:用户请求资源A,资源A处理完将请求转发给资源B处理

    1
    2
    //在资源A的doGet()中调用
    request.getRequestDispatcher("资源B路径").forward(request,response);

转发时共享数据

1
2
3
// /RequestDemo1 的 doGet()
request.setAttribute("msg","helloB");
request.getRequestDispatcher("/RequestDemo2").forward(request,response);
1
2
// /RequestDemo2 的 doGet()
request.getAttribute("msg");//hello

Response

  • 使用 Response 对象设置响应数据

  • Response 继承结构与 Request 类似

Response 设置响应数据

调用 response 相应方法设置响应数据

  1. 响应行 HTTP/1.1 200 OK
    • void setStatus(int sc) : 设置响应状态码
  2. 响应头 Content-Type:text/html
    • void setHeader(String name, String value) : 设置响应头键值对
  3. 响应体
    • printWriter() : 获取字符输出流
    • ServletOutputStream getOutputStream() : 获取字节输出流

Response 完成重定向

  • 重定向(Redirct):一种资源跳转方式

  • 使用场景:用户请求资源A,但资源A无法完成请求,资源A将请求重定向到资源B

  • 服务器向浏览器发起重定向响应, 状态码为 302,浏览器访问响应响应头中 Location 对应 URL

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

//简化写法
response.sendRedirect("/webDemo/ResponseDemo2");
  • 与请求转发不同,重定向资源路径需要加上虚拟目录

重定向与请求转发对比

重定向特点

  • 浏览器地址栏发生变化
  • 可以重定向到任意资源,既能重定向到服务器内部,也能重定向到服务器外部
  • 两次请求,不能在多个资源使用 request 共享数据

请求转发特点

  • 浏览器地址栏不发生变化
  • 只能转发到当前服务器内部资源
  • 一次请求,多个资源共享 request 数据

路径问题

  • 明确路径给谁使用
    1. 给浏览器使用:需要添加虚拟目录(项目访问路径)
    2. 给服务器使用: 不需要添加虚拟目录
  • 使用虚拟目录时使用 request.getContextPath() 动态获取目录

Response 响应字符数据

  1. 获取字符输出流

    1
    PrintWriter writer = response.getWriter();
  2. 写数据

    1
    write.write("<h1>aaa</h1>");//浏览器当作纯文本输出
  3. 若需浏览器解析为 HTML ,需设置头信息

    1
    response.setHeader("content-type","text/html");
  • write 流不需要手动关闭,随 response 销毁自动关闭

  • 输出中文数据需要设置流的编码

    1
    2
    //设置响应头的同时设置输出流的字符集
    response.setContentType("text/html;charset=utf-8");

Response 响应字节数据

  1. 获得字节输出流

    1
    ServletOutputStream outputStream = response.getOutputStream();
  2. 读取文件

    1
    FileInputStream fis = new FileInputStream("a.jpg");
  3. 拷贝字节流

    • 直接拷贝
    1
    2
    3
    4
    5
    byte[] buf = new byte[1024];
    int length = 0;
    while((length = fis.read(buf))!=-1) {
    outputStream.write(buf);
    }
    • 使用工具类

      pom.xml 中导入 commons-io

      1
      2
      3
      4
      5
      6

      <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
      </dependency>
    • 调用 copy 方法

      1
      IOUtils.copy(fis,outputStream);
  4. 关闭文件

    1
    fis.close()

Request & Response
http://mrzzzz1.github.io/2023/03/16/Request/
作者
Mrzzzz1
更新于
2023年3月22日
许可协议