概念

Hyper Text Transfer Protocol 超文本传输协议

传输协议

定义了 客户端和服务器端通信时,发送数据的格式

特点

  • 基于TCP/IP的高级协议
  • 默认端口号:80
  • 基于 请求/响应 模型的 : 一次请求对应一次响应
  • 无状态的 : 每次请求之间相互独立,不能交互数据

历史版本
1.0 :每一次请求响应都会建立新的连接
1.1 :复用连接

请求消息数据格式

  1. 请求行

请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
请求方式
HTTP协议有7种请求方式,常用的有2种:
GET:

  1. - 请求参数在请求行(网址)中,在url `localhost/demo3?username=xx`
  2. - 请求的url长度**有限制**
  3. - 不太安全

POST:

  - 请求参数在请求体中
  - 请求的url长度**无限制**
  - 相对安全
  1. 请求头:客户端浏览器告诉服务器一些信息

格式:请求头名称:请求头值
常见的请求头:

  • User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
    • 可以在服务器端获取该头信息,解决浏览器的兼容性问题
  • Refererhttp://localhost/login.html
    • 告诉服务器,当前请求从哪里来
      • 作用:
        • 防盗链:
        • 统计工作 :例:广告点击来源统计
          1. 请求空行

空行->分隔作用

  1. 请求体(正文)

参数: username = xxx
封装POST请求消息的请求体(参数)的
字符串格式:
GET /login.html HTTP/1.1
Host: localhost
User-Agent:
Accept:
Accept-Language
Accept-Encoding
Referer
Connection
Upgrade-Insecure-Requests:

响应消息数据格式

响应消息:服务器端发送给客户端端数据

数据格式

  • 响应行
    • 组成:协议/版本 响应状态码 状态码描述
      • HTTP/1.1 200 OK
    • 响应状态码
      • 服务器告诉客户端浏览器本次请求和响应的状态
      • 分类
        • 1xx : 服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码
        • 2xx : 成功,例子:200
        • 3xx : 重定向。例子:302(重定向)-> 资源跳转;304(访问缓存)
        • 4xx : 客户端错误
          • 例子
            • 404 (请求路径没有对应资源)
            • 405 (请求方式没有对应的doXX方法 doGet/doPost
        • 5xx : 服务器端错误 例子 500 (服务器内部出现异常)
  • 响应头
    • 格式: 头名称 :值
    • 常见的响应头:
      • Content-Type:服务器告诉客户端本次响应消息体数据格式以及编码格式 text/html;charset=UTF-8
      • Content-disposition:服务器告诉客户端以什么格式打开响应体数据
        • 值:
          • in-line:默认值,在当前页面内打开
          • attachment;filename=xxx:以附件形式打开响应体。 -> 文件下载
  • 响应空行
  • 响应体

HTML页面内容

响应字符串格式
HTTP/1.1 200 OK

Request对象

request对象和response对象原理

截屏2020-10-30 12.20.33.png

  1. request和response对象是由服务器创建的,我们只使用他们
  2. request对象是来获取请求消息,response对象是来设置响应消息

    Request继承体系结构

    ServletRequest —接口
    | 继承
    HttpServletRequest —接口
    | 实现
    org.apache.catalina.connector.RequestFacade 类(tomcat)

Request 获取请求消息

  • 获取请求消息数据
    • 获取请求行数据
      • GET /day14/demo1?name=xx HTTP/1.1
      • 方法:
        • 获取请求方式: GET
          • String getMethod()
        • 🌟获取虚拟目录 : /day14
          • String getContextPath()
        • 获取Servlet路径: /demo1
          • String getServletPath()
        • 获取get方式请求参数 : name=xx
          • String getQueryString()
        • 🌟获取请求URI : /day14/demo1

URL:统一资源定位符
URI:统一资源标识符
范围 URI > URL

     - 获取协议及版本:HTTP/1.1
        - `String getProtocol()`
     - 获取客户机的IP地址
        - `String getRemoteAddr()`
  • 获取请求头数据

    • 方法:
      • 🌟String getHeader(String name) :通过请求头的名称获取请求头的值
      • Enumeration<String> getHeaderNames() :获取所有的请求头名称
        while(headerNames.hasMoreElements()){
         String name = headerNames.nextElement();
         String header = req.getHeader(name);
         System.out.println(name+"--"+header);
        }//循环打印请求头
        
  • 获取请求体数据

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

      • 获取流对象

        • BufferedReader getReader() :获取字符输入流,只能操作字符数据
        • ServletInputStream getInputStream() 获取字节输入流,可以操作所有类型数据
      • 从流对象中拿数据

        • 🌟🌟其他功能
  • 获取请求参数(通用方式: 无论是get还是post都可以使用下列方法

    • String getParameter(String name) 根据参数名称获取参数值
      • 例: (username=roderick&password=123) 根据username能够获取roderick : req.getParameter(“username”);
    • String[] getParameterValues(String name) 根据参数名称获取参数值的数组
      • 例: hobby=xx&hobby=game
    • Enumeration<String> getParameterNames() 获取所有请求的参数名称
    • Map<String,String[]> getParameterMap() 获取所有参数的map集合

    • 中文乱码问题

      • get方式:tomcat8将get方法乱码问题解决了
      • post方式:出现乱码
        • 解决:在获取参数前 设置流的编码
  • 请求转发:一种在服务器内部的资源跳转方式

    • 步骤:

      • 通过request对象获取请求转发器对象 RequestDispatcher getRequestDispatcher(String path)
      • 使用RequestDispatcher对象来进行转发: forward(ServletRequest request,ServletResponse response)
        req.getRequestDispatcher("/requestDemo8").forward(req,resp);
        
    • 特点:

      • 浏览器地址栏路径没有发生变化
      • 只能转发到当前服务器内部资源中
      • 转发是一次请求
  • 共享数据

    • 域对象:一个有作用范围的对象,可以在范围内共享数据
    • request域:代表一次请求,一般用于请求转发的多个资源中共享数据
    • 方法
      • setAttribute(String name,Object obj) 存储数据
      • Object getAttribute(String name) 通过键获取值
      • removeAttribute(String name) 通过键移出键值对
  • 获取ServletContext:
    • ServletContext servletContext = request.getServletContext();
    • org.apache.catalina.core.ApplicationContextFacade@56b51291

      Response对象

      功能:设置响应消息

      设置响应行

      响应行格式: HTTP/1.1 200 ok
  • 设置状态码: setStatus(int sc)

    设置响应头

  • 设置响应头: setHeader(String name, String value)

    设置响应体

    使用步骤:

    • 获取输出流
      • 字符输出流 PrintWriter getWriter()
      • 字节输出流 ServletOutputStream getOutputStream()
    • 使用输出流,将数据输出到客户端浏览器中

案例

完成重定向

重定向:资源跳转的方式

  • 重定向的特点:redirect
    • 地址栏发送变化
    • 重定向可以访问其他站点(服务器)的特点
    • 重定向是两次请求,不能使用request域对象共享数据

截屏2020-11-17 14.13.54.png

  • 转发的特点:forward
    • 转发地址栏路径不变
    • 转发只能访问当前服务器下的资源
    • 转发是一次请求,可以使用request域对象共享数据

路径写法:

  • 相对路径:通过相对路径不可以确定唯一资源呢
    • 如 : ./index.html
    • . 开头
    • 规则:找到当前资源和目标资源之间的相对位置关系
      • ./ :当前目录
      • ../ 后退一级目录
  • 绝对路径:通过绝对路径可以确定唯一资源呢

    • 如:http://localhost/JavaEE/responseDemo1 -> /JavaEE/responseDemo1
    • 规则:判断定义的路径是给谁用的?判断请求将来从哪儿发出

      • 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)【重定向
        • 建议虚拟目录动态获取: request.getContextPath()
      • 给服务器使用:不需要加虚拟目录【转发 ```java //访问/responseDemo1,会自动跳转到/responseDemo2资源 //1-设置状态码为302 // resp.setStatus(302); // //2-设置响应头location // resp.setHeader(“location”,”/JavaEE/responseDemo2”);

      //简单的重定向方法 resp.sendRedirect(“/JavaEE/responseDemo2”); //重定向路径:可以写成http://www.baidu.com ```

      服务器输出字符数据到浏览器

      步骤:

  • 获取字符输出流
  • 输出数据

注意:

  • 乱码问题:

    • PrintWriter pw = resp.getWriter(); 获取的流的默认编码是ISO-8859-1
    • 设置该流的默认编码
    • 告诉浏览器响应体使用的编码
      //简单的形式,设置编码(在获取流之前设置
      resp.setContentType("text/html;charset=utf-8");
      

      服务器输出字节数据到浏览器

      步骤:
  • 获取字节输出流

  • 输出数据

    验证码

  • 本质:图片

  • 目的:防止恶意表单注册 ```java

      int width=100;
      int height=50;
      //创建一个对象,在内存中代表一个图片(验证码图片对象)
      BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
      //美化图片
      //填充背景色
      Graphics g = image.getGraphics();//画笔对象
      g.setColor(Color.PINK);//设置画笔颜色
      g.fillRect(0,0,width,height);//填充
    
      //画边框
      g.setColor(Color.BLUE);
      g.drawRect(0,0,width-1,height-1);//画线条
    
      String str ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopgqrstuvwxyz0123456789";
      //生成随机角标
      Random ran = new Random();
      for (int i = 1; i <=4 ; i++) {
          int index = ran.nextInt(str.length());//随机角标
          //获取字符
          char ch = str.charAt(index);//随机字符
          //写验证码
          g.drawString(ch+"",width/5*i,height/2);
      }
      //画干扰线
      g.setColor(Color.green);
      for (int i = 0; i <10 ; i++) {
          //随机生成坐标点
          int x1 = ran.nextInt(width);
          int x2 = ran.nextInt(width);
          int y1 = ran.nextInt(height);
          int y2 = ran.nextInt(height);
          g.drawLine(x1,y1,x2,y2);
      }
    
    //将图片输出到页面展示
    /*ServletOutputStream outputStream = resp.getOutputStream();
    outputStream.write("<h1>image</h1>".getBytes());*/
    ImageIO.write(image,"jpg",resp.getOutputStream());
<a name="gO75D"></a>
#### 验证码点击切换
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        /**
         * 点击超链接或者图片,需要换一张
         * 1-给超链接和图片绑定单击时间
         * 2-重新设置图片到src属性值
         */
        window.onload=function () {
            //1获取图片对象
            var img = document.getElementById("checkCode");
            //2绑定单击事件
            img.onclick=function () {
                //加时间戳(防止重复缓存
                var date = new Date().getTime();
                img.src="/JavaEE/checkCode?"+date;
            }
            var change = document.getElementById("change");
            change.onclick=function () {
                //加时间戳(防止重复缓存
                var date = new Date().getTime();
                img.src="/JavaEE/checkCode?"+date;
            }
        }
    </script>
</head>
<body>
        <img id="checkCode" src="/JavaEE/checkCode" >

        <a id="change" href="#">看不清?换一张</a>
</body>
</html>