Bootstrap

javaee之http协议、request请求

http协议:Hyper Text Transfer Protocol

超文本传输协议,他的底层是依附于TCP/IP传输协议,所以也是数据的传输也是比较安全的。因为从TCP/IP的层面来说,数据会建立三次握手,然后才会传输数据啊,非常严谨。

最直观来说,输入网址,就是调用什么,http协议,然后进行一个客户端与服务器之间的一个通信。

那么具体的http协议是啥?

从目前来看,分为三个版本,一个是1.0,一个是1.1,一个是2.0,现在用的最多的就是1.1,那么现在https基本就是基于1.1的版本,那么1.1的好处?好处就是链接一个复用,就是说他不会立刻就把一个TCP/IP连接给关闭,就是我等你一会啊,你要是不在用了,那我就关闭了啊。特点就是快嘛,但是相对于2.0还是有点慢。

简单说一下这三个版本,1.0呢,特点是每一次传输开一个TCP/IP,那么也就是说有一百个请求,我就要开一百次传输连接,我去,你说慢不慢,每一次又要带一些请求头部数据过去,数据又会变大,传输自然也会变慢。

1.1呢,特点就是我整个过程只开一次TCP/IP连接,换句话说,有一百个请求,那我也只会开一个TCP连接用来传输,也就是长连接,特点就是快嘛,但是这里有个问题就是,每次新的传输发生之前,会在头部添加一些信息,比如说,表明我是复用之前的连接来传输数据,所以,这个时候,头部数据就会增加,数据包含量就会比较大,但是它有一个缺点就是,数据传输必须一个一个传输,一个传输完成才能进行下一个传输

2.0,这个牛逼了,长连接是必须的,并且,数据包比较小,不用去声明,另外就是并发性比较好,一次可以传输多个文件,而1.1只能一个文件传输完成才能传输另外一个。虽然一次可以传输多个文件,但是最后在客户端展示的时候,依然会按照我们的请求顺序来展示图片内容。

那么这里延伸出一个问题,什么是一次互联网请求?

简单就说,你访问一个网站的页面,这个页面涉及了很多数据,比如图片,视频,文档,等等,那么每一个访问,都是一次请求。展示一下这些请求

建议采用火狐浏览器浏览。下面访问百度产生的一些列请求

下面就是说,具体说一下http1.1的这个内容:

上面就是请求头部数据

上面组成如下:

第一行请求行-》数据传输方式

后面连续的数据就是请求头

请求头简单来说,就是告诉服务器,我是谁,我能接收什么类型数据,我的一些信息是什么。

比如

User-Agent:我用的是哪一个 浏览器

Rferer:告诉服务器我来自哪里

Connection: keep-alive保持TCP连接不断开

 然后有一个空行

空行下面就是请求体数据

用一个图就是:

 上面就是http协议一些简单的内容。

下面说一下我们怎么在服务器端处理这些请求数据。

当然了,服务器开发者怎么会想不到这些,javaee规范早就定义好了,所以,肯定会给我们一个接口去调用方法获取这些信息。

直接上这些接口的依附关系

我们要用到的就是HttpServletRequest这个接口, 通过上面的依附关系很明显就可以看到Tomcat帮我们做了一个实现类,其实我们调用的就是实现类里面的方法:

 doGet里面帮我们传递了请求对象,它的本质就是:

HttpServletRequest resquest = new RequestFacade();

然后去调用子类的方法:

下面说几个常见的Request方法:

        1.getMethod()获取资源请求方式

        2.getConTextPath()获得虚拟目录

        3.统一资源标识符与统一资源定位符,特别是URI定位符,用的比较多

        4.getRemoteAddr()获得远程主机地址

关于请求头的一些操作:

代码:

package web.request;

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("/ServletDemo2")
public class ServletDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //下面来获取所有请求头名称
        Enumeration<String> headerNames = request.getHeaderNames();

        //下面来遍历请求头信息
        while(headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            String  value = request.getHeader(name);
            System.out.println(name + ":" + value);
        }

        System.out.println("新行来了");
        System.out.println("又来了新的一行");
        System.out.println("-------------");
        //得到你来的路径
        String referer = request.getHeader("referer");
        System.out.println("N你的访问路径:" + referer);
    }
}

 获取请求体的数据,这个数据也就是我们传输的数据

 注意上面获取的是请求体中的数据,就是通过post或者get提交过来的数据

话不多说,上代码:

ServletDemo3:

package web.request;

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("/ServletDemo3")
public class ServletDemo3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求体信息
        //post获取参数可能会出现中文乱码问题
        request.setCharacterEncoding("utf-8");
        //1.获取字符流
        BufferedReader br = request.getReader();
        //读取数据,获取post里面传来的数据
        String line = null;
        while((line = br.readLine()) != null) {
            System.out.println(line);
        }
    }

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

    }
}

我又写了一个html页面去访问它:

regist.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/request/ServletDemo3" method = "post">
        <input type="text" name="username"/><br/>
        <input type="text" name="password"/><br/>
        <input type="submit" value="注册"/>
    </form>
</body>
</html>

打印了如下信息:

这个信息很明显,名字是经过了加密处理的

下面我采用字节流来读取一下数据:

 

 

这字节流是javaee帮我们做了一个实现,说到底还是调用了字节流里面的方法

还是同一个文件,替换成字节流读取代码就行

        //当然,我们还可以采用字节流来读取数据
        InputStream is = request.getInputStream();//用父类做了一个接收
        //循环读取数据
        byte[] buff = new byte[1024];
        int len = 0;
        while((len = is.read(buff)) != -1) {
            System.out.println(new String(buff,0,len));
        }

 结果:

 获取其他请求参数方式:

 

话不多说,直接上代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/request/ServletDemo4" method = "get">
        <input type="text" name="username" placeholder="请输入用户名"/><br/>
        <input type="text" name="password" placeholder="请输入密码"/><br/>
        <input type="checkbox" name="hobby" value ="name"/>游戏
        <input type="checkbox" name="hobby" value ="football"/>足球
        <input type="checkbox" name="hobby" value ="name"/>游戏
        <input type="submit" value="注册"/>
    </form>
</body>
</html>

 上面做了一个静态页面去向访问服务器的ServletDemo4页面

package web.request;

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;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

@WebServlet("/ServletDemo4")
public class ServletDemo4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //得到所有请求,然后迭代
        Enumeration<String> enumeration = request.getParameterNames();
        //上面就是返回一个迭代器对象
        while(enumeration.hasMoreElements()) {
            //参数名字拿出来
            String name = enumeration.nextElement();
            //把这些数据变成数组
            System.out.println(name);//得到属性名,来取属性值
            String[] value = request.getParameterValues(name);
            for(String data : value) {
                System.out.println(data);
            }
            System.out.println("-----");
        }

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

        //获取所有参数的map集合,属性-值名,前者是属性,后者是值的一个数组集合
        Map<String,String[]> parameterMap = request.getParameterMap();

        //开始迭代
        Set<String> set = parameterMap.keySet();

        //获取键值对
        Iterator<String> it = set.iterator();

        while(it.hasNext()){
            String name = it.next();//这个就是每一个元素
            //然后取出值
            System.out.println(name + ":");
            //这里每一个值都是一个数组
            String[] value = parameterMap.get(name);
            //再来遍历
            for(String data : value) {
                System.out.println(data);
            }
        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

上面用了两种方式获取数据

这是我提交的数据

 

 上面打印的乱码,和文件保存编码有关系,通过记事本打开,另存修改编码就不是乱码了。

下面在多说一嘴,获取请求体-》两种输入流操作-》可以得到post请求的数据,也是请求参数

上面的方法,是一种通用的方法,post请求参数与get请求参数都可以获取

下面说一下服务器内部的一个资源跳转,这个跳转其实也很简单,就是我服务器内部带着requestd对象还有response对象去找我的兄弟页面。自然,内部跳转,浏览器地址不会改变,转发就是一次请求,只能到服务器内部。

在转发的过程中,resquest之间可以共享

话不多说,直接上代码

ServletDemo5.java

package web.request;

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("/ServletDemo5")
public class ServletDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("我是deom5,我要跳转到Demo6....");
        //设置一个属性传过去
        request.setAttribute("msg","我爱你demo6");
        //开始定向
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/ServletDemo6");
        requestDispatcher.forward(request,response);//定向到Demo6
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

 上面demo5就带着自己的数据去找Demo6了

ServletDemo6.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("/ServletDemo6")
public class ServletDemo6 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取数据
        Object msg = request.getAttribute("msg");
        System.out.println("我是Demo9,传递过来的信息是:" + msg);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

 Demo6就去获取了一下数据

是不是就死说两边数据都可以打印,但是如果Demo7想要获取Demo5的数据,那是不可能的,因为数据的共享是在一次请求范围之间。

好了,resquest大致就说到这。

 

;