HTTP

HTTP

1. 概念

超文本传输协议(HyperText Transport Protocol),基于TCP/IP的应用层协议,默认端口号是80,基于请求响应模型(一次请求对应一次响应),是无状态的(每次请求是项目独立的)。

  1. 1.0版本:每次请求响应都会建立一次HTTP连接
  2. 1.1版本:HTTP连接会被复用,一次连接可以传输多次数据

2. Request对象和Response对象

  1. 服务器在收到一次请求消息后做的事情:
    1. Tomcat服务器根据请求URL的资源路径创建对应的Servlet对象
    2. Tomcat服务器创建Request对象和Response对象,其中在Request对象中封装请求消息数据
    3. Tomcat将Request对象和Response对象传递给service方法,并且通过Servlet对象调用该方法
    4. 在该方法中,可以根据Request对象获取请求消息数据,并通过Response对象设置响应消息数据
    5. 服务器在给浏览器做出响应之前会从Response对象中得到设置好的响应消息数据

3. HTTP请求消息数据格式

  1. Request对象的继承体系结构:

    ServletRequest -- 接口
    	|继承
    HttpServletRequest -- 接口
    	|实现
    RequestFacade -- 实现类
    

    该实现类有Apache编写,org.apache.catalina.connector.RequestFacade

  2. 请求行

    请求方法 请求URL 请求协议/版本
    
    1. 请求方法:HTTP有7中请求方式,常用的有两种
      1. GET:
        1. 请求参数在请求行中(在URL后)
        2. 请求的URL长度有限制
        3. 相对没那么安全
      2. POST:
        1. 请求参数在请求体中
        2. 请求URL长度没有限制
        3. 相对安全
  3. 请求头

    请求头名称:请求头值
    

    常用的请求头:

    1. User-Agent:告诉服务器浏览器版本信息
      1. 可以用来解决浏览器版本兼容性问题
    2. Accept:可以接收、解析的信息
    3. Connection:keep-alive,1.1版本、连接复用
    4. Referer:Referer: http://localhost/login.html,告诉服务器,当前请求是从哪里来的
      1. 作用有:防止盗链、统计流量来源数量等
  4. 请求空行:就是一个空行,用来分隔请求头和请求体

  5. 请求体:封装POST请求消息的请求参数的

    1. GET方法没有请求体,POST方法的请求体为 name=值
  6. 一个简单的完整的请求消息如下:

    POST /demo3 HTTP/1.1 -- 请求行
    Host: localhost
    Connection: keep-alive
    Content-Length: 13
    Cache-Control: max-age=0
    Origin: http://localhost
    Upgrade-Insecure-Requests: 1
    Content-Type: application/x-www-form-urlencoded
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    x-xyst: KHgiNG8mJjdUdnVPSnIxRYrXQyBkSfrS47T_FU7_372biFAU4QMaRw==
    Referer: http://localhost/login.html
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9,is;q=0.8,zh;q=0.7,zh-CN;q=0.6,zh-TW;q=0.5,ja;q=0.4,nl;q=0.3
    Cookie: Idea-ba272247=a33d6b38-3af8-4b08-b337-f1e8c3cc1311; JSESSIONID=F43308216BD55AAF85AF182BEA04824F
    														-- 请求空行
    														
    username=bobby -- 请求体
    
    

4.Request对象的功能

  1. 获取请求消息数据

    1. 获取请求行数据,假如请求行是这个:GET /servlet/demo3?username=aaa HTTP/1.1

      1. 获取请求方式(GET):String getMethod()
      2. (*)获取虚拟目录(/servlet):String getContextPath(),一般用来动态获取虚拟目录,而不是写死。
      3. 获取Servlet路径(/demo3):String getServletPath()
      4. 获取get方式的请求参数(username=aaa):String getQueryString()
      5. (*)获取请求的URI(/servlet/demo3)
        1. String getRequestURI(): /servlet/demo3
        2. String getRequestURL(): http://localhost/servlet/demo3
      6. 获取协议版本(HTTP/1.1):String getProtocol()
      7. 获取客户机的IP地址:String getRemoteAddr()
    2. 获取请求头数据

      1. String getHeader(String name):根据请求头名称,获取请求头的值
      2. Enumeration< String > getHeaderNames():获取所有的请求头名称
    3. 获取请求体的数据

      1. 只有POST方法才有请求体,在请求体中封装了POST请求的请求参数

      2. 步骤:

        1. 获取流对象

          1. BufferReader getReader():获取字符输入流,只能操作字符数据
          2. ServletInputStream getInputStream():获取字节输入流,可以操作所有的数据类型
        2. 从流对象里拿到参数数据

          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              BufferedReader br = request.getReader();
              String str = null;
              while ((str = br.readLine()) != null) {
                  System.out.println(str);// username=bbbb&password=bbbb
              }
          }
          
  2. 其他的功能

    1. 获取请求参数的通用方式(兼容GET和POST)

      1. String getParameter(String name) :根据参数名获取参数值
      2. String[] getParameterValues(String name):根据参数名获取参数值的数组,针对复选框的情况
      3. Enumeration< String > getParameterNames():获取所有请求的参数名
      4. Map<String, String[]> getParameterMap():获取所有参数的map集合

      注意:获取请求参数时会可能出现乱码情况,修改编码格式即可:

      request.setCharacterEncoding("utf-8"); -- utf-8为输入参数的注册页面格式
      
    2. 请求转发:一种在服务器内部的资源跳转方式

      1. 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)

      2. RequestDispatcher对象调用forward方法进行转发:forward(ServletRequest request,ServletResponse)

        System.out.println("demo8888888888888888");
        request.getRequestDispatcher("/requestDemo7").forward(request,response);
        
        // 这样不仅可以访问到demo8,还可以访问到demo7,因为在demo8里请求转发到demo7
        
      3. 请求转发的特点:

        1. 浏览器地址栏的路径不会改变
        2. 只能请求转发本服务器内部的资源,不能请求其他资源
        3. 转发只是一次请求,不会因为访问了多个资源就是多个请求
    3. 共享数据:请求转发实际上是两个Servlet之间的通信,可以使用共享数据的方法进行通信,一个Servlet了可以存储数据,另一个Servlet可以读取数据

      1. 域对象:一个有作用范围的对象,可以在范围内共享数据
      2. request域:值得是一次请求的范围,该范围可以因为请求转发而被扩大,一般用于在发生请求转发的多个资源中进行数据的共享。
      3. 方法:
        1. void setAttribute(String name, Object obj):存储数据
        2. Object getAttribute(String name):根据键获取数据
        3. void removeAttribute(String name):根据键移除数据
    4. 获取ServletContext

      1. 方法:servletContext getServletContext()

5. HTTP响应消息的数据格式

  1. 响应行

    HTTP/1.1 200 OK
    

    组成:协议版本、响应的状态码、响应的状态

    状态码对应的状态:

    1. 1XX:服务器接收到信息,但是没有完成,在等待一段时间后,发送1XX给客户端
    2. 2XX:成功,如:200
    3. 3XX:重定向,如:302(重定向)、304(访问缓存)
    4. 4XX:客户端错误,如:404(访问路径没有对应资源)、405(请求方法没有对应的doGet或者doPost方法)
    5. 5XX:服务器内部出现异常,如:500(服务器内部出现异常)
  2. 响应头

    Content-Type: text/html;charset=UTF-8
    Content-Length: 101
    Date: Thu, 25 Apr 2019 07:43:37 GMT
    

    格式:响应头名称:响应值

    常见的响应头:

    1. Content-Type:服务器告知客户端本次响应的数据格式以及编码方式
    2. Content-Length:响应体的长度,以字节为单位
    3. Content-disposition:服务器告诉客户端以什么格式打开响应体的数据
      1. 值为 in-line:默认值,在当前页面打开响应体
      2. 值为 attachment;filename=xxx:以附件形式打开响应体,一般用于文件下载
  3. 响应空行

  4. 响应体:真实的传输的数据

    <html>
      <head>
        <title>index.jsp</title>
      </head>
      <body>
        response.jsp
      </body>
    </html>
    

6. Response对象的功能

  1. 设置响应消息

    1. 设置响应行:HTTP/1.1 200 OK
      1. 设置状态码:setStatus(int sc)
    2. 设置响应头:setHeader(String name, String value)
    3. 设置响应体:
      • 使用步骤:
        1. 获取输出流
          1. 获取字节输出流:ServletOutputStream getOutputStream()
          2. 获取字符输出流:PrintWriter getWrite()
        2. 使用输出流影数据输出到浏览器
  2. Response对象的功能:

    1. 实现重定向

      1. 代码实现
      response.setStatus(302);
      response.setHeader("location", "/response/ResponseDemo2");
      /***********或者**************/
      response.sendRedirect("/response/ResponseDemo2");
      
      1. 重定向和转发的区别

        重定向(redirect) 转发(forward)
        地址栏发生变化 地址栏不发生变化
        可以访问其他站点的资源 只能访问本服务器内部的资源
        重定向是两次请求 转发是一次请求

        解析:由于转发是一次请求,因此可以使用Request对象来共享数据,但是重定向是两次请求,因此有两个Request对象,不能通过Request对象共享数据。

      2. 路径的写法:

    2. 输出数据

      1. 服务器输出字符到浏览器:

        //获取字符输出流之前先设置编码格式为utf-8,避免中文乱码
        response.setContentType("text/html; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("<h1>我写几个中文吧,hello, i am a response message!</h1>");
        
      2. 服务器输出字节浏览器:(一般用来输出图片等信息)

        response.setContentType("text/html; charset = utf-8");
        ServletOutputStream os = response.getOutputStream();
        os.write("猪八戒".getBytes());
        
      3. 验证码的小demo

        @WebServlet("/checkCodeServlet")
        public class CheckCodeServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doGet(request, response);
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                int width  = 100;
                int height = 50;
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        
                // 填充背景色
                Graphics graphics = image.getGraphics();
                graphics.setColor(Color.pink);
                graphics.fillRect(0, 0, width, height);
        
                // 画边框
                graphics.setColor(Color.BLUE);
                graphics.drawRect(0, 0, width - 1, height - 1);
        
                // 随机画四个字母
                String str = "ABCDEFGHIJKLMNOPQTSTUVWXYZabcdefghijkilmnopqrstuvwxyz0123456789";
                Random random = new Random();
                for(int i = 1; i < 5; i++) {
        
                    int index = random.nextInt(str.length());
                    char c = str.charAt(index);
                    graphics.drawString(c+"", i * 20, height / 2);
                }
        
                // 随机画干扰线
                graphics.setColor(Color.GREEN);
                for(int i = 0; i < 15; i++) {
                    int x1 = random.nextInt(width);
                    int y1 = random.nextInt(height);
                    int x2 = random.nextInt(width);
                    int y2 = random.nextInt(height);
                    graphics.drawLine(x1, y1, x2, y2);
                }
        
                boolean jpg = ImageIO.write(image, "jpg", response.getOutputStream());
            }
        }
        

        验证码切换

        <script>
            window.onload = function () {
                var image = document.getElementById("checkCode");
                image.onclick = function () {
                    // 由于其实每次都是访问一样的Servlet,因此要加时间戳,欺骗服务器每次请求不一样,这样就可以不访问浏览器的本地缓存
                    var date = new Date().getTime();
                    image.src = "/response/checkCodeServlet" + "?" + date;
                }
                
                var link = document.getElementById("change");
                link.onclick = function () {
                    var date = new Date().getTime();
                    image.src = "/response/checkCodeServlet" + "?" + date;
                }
            }
        </script>
        

7. ServletContext对象

ServletContext对象概念:ServletContext用来存放全局变量,每个Java虚拟机每个Web项目只有一个ServletContext,这个ServletContext是由Web服务器创建的,来保证它的唯一性。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象通讯。ServletContext对象通常也被称之为Context域对象。来源:JAVA School

  1. 获取ServletContext对象:要注意两种方法获取的ServletContext对象是同一个,因为一个项目就唯一的一个Servlet对象。

    • Request对象的getServletContext方法

      ServletContext context1 = request.getServletContext();
      
    • HttpServlet对象的方法(自己写的Servlet继承了HttpServlet)

      ServletContext context2 = this.getServletContext();
      
  2. 获取MIME类型

    1. MIME(Multipurpose Internet Mail Extensions)类型

            最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户程序解释为超文本标记语言HTML 文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型。MIME意为多功能Internet邮件扩展,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,让邮件客户程序能根据其类型进行处理。然而当它被HTTP协议支持之后,它的意义就更为显著了。它使得HTTP传输的不仅是普通的文本,而变得丰富多彩。每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
      常见的MIME类型(通用型):
      超文本标记语言文本 .html text/html
      xml文档 .xml text/xml
      XHTML文档 .xhtml application/xhtml+xml
      普通文本 .txt text/plain
      RTF文本 .rtf application/rtf
      PDF文档 .pdf application/pdf
      Microsoft Word文件 .word application/msword
      PNG图像 .png image/png
      GIF图形 .gif image/gif
      JPEG图形 .jpeg,.jpg image/jpeg
      au声音文件 .au audio/basic
      MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
      RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
      MPEG文件 .mpg,.mpeg video/mpeg
      AVI文件 .avi video/x-msvideo
      GZIP文件 .gz application/x-gzip
      TAR文件 .tar application/x-tar

    2. ServletContext对象获取MIME类型的方法

      1. String getMimeType():

        String filename = "p.jpg";
        String mimeType = context1.getMimeType(filename);
        System.out.println(mimeType);
        //输出 image/jpeg ,表明JPG文件的MIME类型是 image/jpeg
        
    3. 域对象:共享数据

      ServletContext域代表着整个web项目,这个域是最大的,可以共享所有用户所有请求的数据,该对象的声明周期很长,从服务器启动到服务器关闭,一般来说使用该对象存储数据应该谨慎,因为很容易就造成服务器的压力。和Request域类似,也是有三个方法存储数据,获取数据,移除数据:

      1. void setAttribute(String name, Object obj):存储数据
      2. Object getAttribute(String name):根据键获取数据
      3. void removeAttribute(String name):根据键移除数据
    4. 获取文件的真实路径(Tomcat服务器路径)

      1. 方法:String getRealPath(String 资源名称)

        返回资源的真实路径, 根据资源的具体位置不同不同参数有不同的写法,资源位置一般是在:

        • web目录下:"/a.txt"
        • web目录下的WEB-INF目录下:"/WEB-INF/a.txt"
        • src目录下:"/WEB-INF/classes/a.txt"
          • 当然src下的资源还可以通过classloader来获取
原文地址:https://www.cnblogs.com/zhuobo/p/10776798.html