本文最后更新于:4 个月前

接着上篇博文 《HTTP:超文本传输协议》 的学习。

现在,来学习两个对象:Request & Response。

request对象和response对象的原理

  1. request和response对象是由服务器创建的。接着我们来使用它们
  2. request对象是来获取请求消息,response对象是来设置响应消息
  3. 其基本原理,如下图👇

Request&Response对象基本原理

request对象继承体系结构

ServletRequest – interface,接口

↓|继承

HttpServletRequest – interface,接口

↓|实现

org.apache.catalina.connector.RequestFacade – 类,Tomcat编写的

Tomcat 是用纯Java语言编写

request功能

  1. 基础功能
    • 获取请求消息数据
  2. 其他功能:
    • 1.获取请求参数通用方式
    • 2.请求转发
    • 3.共享数据
    • 4.获取ServletContext

获取请求消息数据

  1. 获取请求行数据
  2. 获取请求头数据
  3. 获取请求体数据
  1. 获取请求消息数据的字符串格式 👇
POST /login.html	HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1

username=zhangsan

一.获取请求行数据

GET  /day14/demo1?name=zhangsan  HTTP/1.1

调用方法(★★重点掌握):

  1. 获取请求方式:GET
  • String getMethod()
  1. ★★获取虚拟目录:/day14
  • String getContextPath()
  1. 获取Servlet路径:/demo1
  • String getServletPath()
  1. 获取get方式请求参数:name=zhangsan
  • String getQueryString()
  • 不用这个,以后会用更高级的方式
  • 多个参数之间用&连接
  1. ★★获取请求URI:/day14/demo1
  • String getRequestURI():/day14/demo1

  • StringBuffer getRequestURL()http://localhost/day14/demo1

    • URL:统一资源定位符http://localhost/day14/demo1 其地位相当于”中华人民共和国”

    • URI:统一资源标识符,其表示范围更大 :/day14/demo1 其地位相当于”共和国”

  1. 获取协议及版本:HTTP/1.1
  • String getProtocol()

  • 该方法在Interface ServletRequest

  1. 获取客户机的IP地址:
  • String getRemoteAddr()

  • 该方法在Interface ServletRequest

示例

新建RequestDemo1.java,输入代码👇

可以在新建时候选择创建Servlet,IDEA自动生成相应模板。

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 演示Request对象获取请求行数据
 */

@WebServlet("/RequestDemo1")
public class RequestDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
            1. 获取请求方式 :GET
                * String getMethod()
            2. (*)获取虚拟目录:/Servlet
                * String getContextPath()
            3. 获取Servlet路径: /requestDemo1
                * String getServletPath()
            4. 获取get方式请求参数:name=zhangsan
                * String getQueryString()
            5. (*)获取请求URI:/Servlet/requestDemo1
                * String getRequestURI():		/day14/requestDemo1
                * StringBuffer getRequestURL()  :http://localhost/Servlet/requestDemo1
            6. 获取协议及版本:HTTP/1.1
                * String getProtocol()

            7. 获取客户机的IP地址:
                * String getRemoteAddr()

         */
        //1. 获取请求方式 :GET
        String method = request.getMethod();
        System.out.println(method);
        //2.(*)获取虚拟目录:/day14
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //3. 获取Servlet路径: /demo1
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //4. 获取get方式请求参数:name=zhangsan
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //5.(*)获取请求URI:/day14/demo1
        String requestURI = request.getRequestURI();
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);
        //6. 获取协议及版本:HTTP/1.1
        String protocol = request.getProtocol();
        System.out.println(protocol);
        //7. 获取客户机的IP地址:
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
    }
}

演示👇

浏览器访问:http://localhost/Servlet/RequestDemo1?name=zhangsan

IDEA控制台输出:

二.获取请求头数据

Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1

调用方法(★★重点掌握):

  1. ★★String getHeader(String name)
  • 通过请求头的名称获取请求头的值
  • 参数不分大小写,只要单词拼写的对即可
  1. Enumeration<String> getHeaderNames()
  • 获取所有的请求头名称
  • 封装成 Enumeration<String>

注意:从JDK1.0开始,该接口的功能由Iterator(迭代器)接口 复制。此外,Iterator还添加了一个可选的删除操作,并且有较短的方法名称。新的实现应该考虑使用迭代器优选于枚举。——JDK 8 文档

示例

一、调用Enumeration<String> getHeaderNames(),演示获取所有请求头数据

  1. 新建一个Servlet,名为RequestDemo2.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/RequestDemo2")
public class RequestDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 演示获取请求头数据

        // 1.获取所有请求头数据
        Enumeration<String> headerNames = request.getHeaderNames();
        // 2.遍历
        while(headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            // 根据名称获取请求头的值
            String value = request.getHeader(name);
            System.out.println(name + "--" + value);
        }

    }
}
  1. 浏览器访问:http://localhost/Servlet/RequestDemo2
  2. IDEA控制台输出:

二、调用String getHeader(String name),user-agent、referer

  1. 新建一个Servlet,名为RequestDemo3.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 演示获取请求头数据:user-agent(客户端版本)
        
        // 获取请求头数据:user-agent
        String agent = request.getHeader("user-agent");
        // 判断agent的浏览器版本,可以解决浏览器兼容问题
        if(agent.contains("Chrome")) {
            // 谷歌浏览器
            System.out.println("谷歌来了。。。");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            System.out.println("火狐来了。。。");
        }
        
    }
}
  1. 浏览器访问:http://localhost/Servlet/RequestDemo3
  2. IDEA控制台输出:

注意:

获取请求头数据:user-agent(客户端版本)

判断agent的浏览器版本,可以解决浏览器兼容问题

  1. 新建一个Servlet,名为RequestDemo4.java

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 演示请求头数据:referer
        String referer = request.getHeader("referer");
        System.out.println(referer); // http://localhost/Servlet/login.html

        //防盗链
        if(referer != null) {
            if(referer.contains("/Servlet")) {
                // 正常访问
                System.out.println("播放电影。。。");
                /* 等同于,只不过不再是输出到控制台,而是直接打印在页面上
                response.setContentType("text/html;charset=utf-8");
                response.getWriter.writer("播放电影。。。")
                */
            } else {
                // 盗链
                System.out.println("想看电影吗?来优酷吧。。。");
                /* 等同于,只不过不再是输出到控制台,而是直接打印在页面上
                response.setContentType("text/html;charset=utf-8");
                response.getWriter.writer("想看电影吗?来优酷吧。。。")
                */
            }
        }
    }
}
  1. 新建一个html文件,名为login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>表单</title>
</head>
<body>
    <form action="/Servlet/Demo3" method="get">
        <input name="username">
        <input type="submit" value="提交">
    </form>

    <!--加入超链接-->
    <a href="http://localhost/Servlet/RequestDemo4">RequestDemo3</a>

</body>
</html>
  1. 演示👉获取请求头数据:referer

  1. 关于获取referer来防盗链,观看 视频(进度条【10:56】)

三.获取请求体数据

username=zhangsan
  • 请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数

  • 步骤:

    1. 获取流对象
      • 获取字符输入流:文字等字符数据
      • 获取字节输入流:上传图片、文件等字节数据
    2. 再从流对象中获取数据

调用方法:

  1. BufferedReader getReader()
  • 获取字符输入流,只能操作字符数据

  • 返回值是BufferedReader高效的、带有缓冲区的

  • 该方法在Interface ServletRequest

  1. ServletInputStream getInputStream()
  • 获取字节输入流,可以操作所有类型数据

  • 但是获取字符时不方便,更推荐用第一个调用方法

  • 返回值是ServletInputStream继承了InputStream

  • 涉及到文件上传等知识

  • 该方法在Interface ServletRequest

示例

  1. 新建html文件,名为regist.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>

    <form action="/Servlet/RequestDemo5" method="post">
        <input type="text" placeholder="请输入用户名" name="username"><br>
        <input type="text" placeholder="请输入密码" name="password"><br>
        <input type="submit" value="注册">

    </form>

</body>
</html>
  1. 新建一个Servlet,名为RequestDemo5.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;

@WebServlet("/RequestDemo5")
public class RequestDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求消息体--请求参数

        //1.获取字符流
        BufferedReader br = request.getReader();
        //2.读取数据
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }
        br.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}
  1. 浏览器访问:http://localhost/Servlet/regist.html
  2. 控制台输出:

注意:多个参数之间用&连接。

其他功能

  1. 获取请求参数通用方式

  2. 请求转发

  3. 共享数据

一、获取请求参数通用方式

  • 不论GET还是POST请求方式都可以使用下列方法来获取请求参数
  • 上述即,doGet()doPost() 的方法体代码完全一样
  • 因此,为了简化,只需要选择在doPost() 的方法体中写代码,之后在doGet()调用 this.doPost(request,response);

调用方法:

  1. String getParameter(String name)
  • 根据参数名称获取参数值: username=zs&password=123
  1. String[] getParameterValues(String name)
  • 根据参数名称获取参数值的数组:hobby=xuexi&hobby=game
  • 将键值对,按一个来封装不同的值并封装成一个数组
  • 多用于复选框
  1. Enumeration<String> getParameterNames()
  • 获取所有请求的参数名称
  1. Map<String,String[]> getParameterMap()
  • 获取所有参数的Map集合

示例

  1. 新建regist2.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>

    <form action="/Servlet/RequestDemo6" method="post">
        <input type="text" placeholder="请输入用户名" name="username"><br>
        <input type="text" placeholder="请输入密码" name="password"><br>

        <input type="checkbox" name="hobby" value="game">游戏
        <input type="checkbox" name="hobby" value="study">学习
        <br>

        <input type="submit" value="注册">

    </form>

</body>
</html>
  1. 新建RequestDemo6.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/RequestDemo6")
public class RequestDemo6 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post 获取请求参数

        //根据参数名称获取参数值
        String username = request.getParameter("username");
       /* System.out.println("post");
        System.out.println(username);*/

       //根据参数名称获取参数值的数组
        String[] hobbies = request.getParameterValues("hobby");
        /*for (String hobby : hobbies) {
            System.out.println(hobby);
        }*/

        //获取所有请求的参数名称

        Enumeration<String> parameterNames = request.getParameterNames();
        /*while(parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();
            System.out.println(name);
            String value = request.getParameter(name);
            System.out.println(value);
            System.out.println("----------------");
        }*/

        // 获取所有参数的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        //遍历
        Set<String> keyset = parameterMap.keySet();
        for (String name : keyset) {
            
            //获取键获取值
            String[] values = parameterMap.get(name);
            System.out.println(name);
            for (String value : values) {
                System.out.println(value);
            }

            System.out.println("-----------------");
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get 获取请求参数
/*
        //根据参数名称获取参数值
        String username = request.getParameter("username");
        System.out.println("get");
        System.out.println(username);*/

        this.doPost(request,response);
    }
}
  1. 浏览器访问:http://localhost/Servlet/regist2.html

  2. 控制台输出:

中文乱码问题

  1. GET方式:tomcat 8 已经将 GET方式乱码问题解决了
  2. POST方式:会乱码
  • 解决:在获取参数前,设置request的编码request.setCharacterEncoding("utf-8"); 。对应着html页面的编码。

二、请求转发

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

特点

  1. 浏览器地址栏路径不发生变化

  2. 只能转发到当前服务器内部资源中

  3. 转发就是一次请求。像上图的AServlet和BServlet两种资源使用的是同一次请求。

步骤

  1. 通过request对象获取请求转发器对象
  • RequestDispatcher getRequestDispatcher(String path)
  1. 使用RequestDispatcher对象来进行转发
  • forward(ServletRequest request, ServletResponse response)

示例

  1. 新建RequestDemo8.java
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/RequestDemo8")
public class RequestDemo8 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Demo8888被访问了。。。");
        //转发到Demo9资源
        /*
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/RequestDemo9");
        requestDispatcher.forward(request,response);
        // 一般不这么写,直接写成:
        request.getRequestDispatcher("/RequestDemo9").forward(request,response);
        */

        //存储数据到request域中
        request.setAttribute("msg","hello");

        request.getRequestDispatcher("/RequestDemo9").forward(request,response);
       //没法跳转到外部资源,比如下面这个是不行的
//request.getRequestDispatcher("http://www.itcast.cn").forward(request,response);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request,response);
    }
}
  1. 新建RequestDemo9.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/RequestDemo9")
public class RequestDemo9 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //获取数据
        Object msg = request.getAttribute("msg");
        System.out.println(msg);

        System.out.println("Demo9999也被访问了。。。");

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request,response);
    }
}
  1. 浏览器访问:http://localhost/Servlet/RequestDemo8
  2. 控制台输出:

三、共享数据

  • 域对象:一个有作用范围的对象,可以在范围内共享数据
  • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

调用方法:

  1. void setAttribute(String name,Object obj)
  • 存储数据
  1. Object getAttitude(String n
  2. ame)
  • 通过获取
  1. void removeAttribute(String name)
  • 通过移除键值对

👉视频 的【03:15】,详细说到 如何共享数据

示例

示例放在 __ 请求转发 的示例 __ 中。

详细见代码文件中的两个注释:

RequestDemo8的【// 存储数据到request域中】

RequestDemo9的【// 获取数据】

四、获取ServletContext

调用方法:

  • ServletContext getServletContext()

示例

  1. 新建RequestDemo10.java
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/RequestDemo10")
public class RequestDemo10 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


        ServletContext servletContext = request.getServletContext();

        System.out.println(servletContext);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request,response);
    }
}
  1. 浏览器访问:http://localhost/Servlet/RequestDemo10
  2. 控制台输出:


下篇博客 《HTTP响应信息数据 - Response》 中,详细学习响应信息数据 - Response


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

2020.2.22随笔 上一篇
HTTP:超文本传输协议 下一篇

 目录