Http协议

什么是Http协议?

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写。HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同, 用于客户端和服务器之间的通信。请求访问文本或图像等资源的一端称为客户端, 而提供资源响应的一端称为服务器端。

协议:是指对方,或者多方,相互约定好,大家都要遵守的规则,叫协议。

所谓 HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议。 HTTP 协议中的数据又叫报文。

请求HTTP协议格式

  • 客户端给服务器发送数据叫请求。
  • 服务器给客户端回传数据叫响应。
  • 请求又分为 GET 请求,和 POST 请求两种
GET请求
  • 请求行

    1. 请求的方式 -->GET
    2. 请求的资源路径**[+?+请求参数]**
    3. 请求的协议的版本号 -->HTTP/1.1
  • 请求头

    key:value组成不同的键值对,表示不同的含义

get请求.png

POST请求
  • 请求行

    1. 请求的方式 -->POST
    2. 请求的资源路径**[+?+请求参数]**
    3. 请求的协议的版本号 -->HTTP/1.1
  • 请求头

    key:value组成不同的键值对,表示不同的含义

  • 空行

  • 请求体:发送给服务器的数据

post请求.png

常用请求头说明
  • Accept: 表示客户端可以接收的数据类型
  • Accpet-Languege: 表示客户端可以接收的语言类型
  • User-Agent: 表示客户端浏览器的信息
  • Host: 表示请求时的服务器 ip 和端口
区分GET请求与POST请求
  • GET请求:
    1. form 标签method=get
    2. a标签
    3. link标签引入css
    4. script标签引入js
    5. img标签引入图片
    6. iframe引入html页面
    7. 在浏览器地址栏中输入地址后回车
  • POST请求:
    1. form标签method=post
响应的HTTP协议格式
  • 响应行
    1. 响应的协议和版本号
    2. 响应状态码
    3. 响应状态描述符
  • 响应头
    1. key:value,不同的响应头,有其不同的含义
  • 响应体:回传给客户端的数据

响应http协议.png

常用响应码说明
响应码解释
200表示请求成功
302表示请求重定向
404表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)
500表示服务器已经收到请求,但是服务器内部错误(代码错误)
MIME 类型说明
文件MIME类型Content-Type
超文本标记语言文本.html, .htmtext/html
普通文本.txttext/plain
RTF 文本.rtfapplication/rtf
GIF 图形.gifimage/gif
JPEG 图形.jpeg,.jpgimage/jpeg
au 声音文件.auaudio/basic
MIDI 音乐文件mid,.midiaudio/midi,audio/x-midi
RealAudio 音乐文件.ra, .ramaudio/x-pn-realaudio
MPEG 文件.mpg,.mpegvideo/mpeg
AVI 文件.avivideo/x-msvideo
GZIP 文件.gzapplication/x-gzip
TAR 文件.tarapplication/x-tar

谷歌浏览器如何查看HTTP协议:

谷歌浏览器如何打开协议.png

其他浏览器查询方式与其相似

HttpServletRequest类

作用

每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。 然后传递到 service 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的 信息。

常用方法

方法描述
getRequestURI()获取请求的资源路径
getRequestURL()获取请求的统一资源定位符(绝对路径)
getRemoteHost()获取客户端的 ip地址
getHeader()获取请求头
getParameter()获取请求的参数
getParameterValues()获取请求的参数(多个值的时候使用)
getMethod()获取请求的方式 GET 或 POST
setAttribute(key, value)设置域数据
getAttribute(key)获取域数据
getRequestDispatcher()获取请求转发对象

相关使用:

public class RequestServlet1 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //getRequestURI()获取请求的资源路径
        System.out.println("URI===>" + request.getRequestURI());
        //getRequestURL()获取请求的统一资源定位符(绝对路径)
        System.out.println("URL===>" + request.getRequestURL());
        //getRemoteHost()获取客户端的 ip地址
        System.out.println("ip地址===>" + request.getRemoteHost());
        //getHeader()获取请求头
        System.out.println("获取请求头===>" + request.getHeader("Accept"));
        //getMethod()获取请求的方式 GET 或 POST
        System.out.println("请求参数GET/POST===>" + request.getMethod());
    }
}

如何获取请求参数

建立一个表单:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="http://localhost:8080/servlet_request/parameter" method="get">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        兴趣爱好:<input type="checkbox" name="hobby" value="篮球">篮球
        <input type="checkbox" name="hobby" value="足球">足球
        <input type="checkbox" name="hobby" value="排球">排球
        <input type="checkbox" name="hobby" value="羽毛球">羽毛球<br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

xml配置:

<servlet>
        <servlet-name>ParameterServlet</servlet-name>
        <servlet-class>com.example.servlet_request.ParameterServlet</servlet-class>
    </servlet>
<servlet-mapping>
        <servlet-name>ParameterServlet</servlet-name>
        <url-pattern>/parameter</url-pattern>
    </servlet-mapping>

使用方法:

public class ParameterServlet extends HttpServlet {


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求参数
        System.out.println("用户:" + request.getParameter("username"));
        System.out.println("密码:" + request.getParameter("password"));
        System.out.println("兴趣爱好:" + request.getParameter("hobby"));   //可以换成getParameterValues(), String[] hobbies = request.getParameterValues("hobby");

    }
}

注意: 假如我们对爱好进行多选的时候就需要使用getParameterValues()获取请求的参数(多个值的时候使用)

请求的中文乱码解决

  • doGet请求的中文乱码解决

    把Tomcat下面conf文件夹下的server.xml文件中:

    <Connector port="8080" protocol="HTTP/1.1"
                   maxThreads="150" connectionTimeout="20000"
                	redirectPort="8443" />
    

    修改为:

    <Connector port="8080" protocol="HTTP/1.1"
                   maxThreads="150" connectionTimeout="20000"
                   redirectPort="8443" URIEncoding="UTF-8" />
    
  • POST请求的中文乱码解决

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
        // 设置请求体的字符集为 UTF-8,从而解决 post 请求的中文乱码问题
        req.setCharacterEncoding("UTF-8");
        System.out.println("-------------doPost------------");
        // 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobby");
        System.out.println("用户名:" + username);
        System.out.println("密码:" + password);
        System.out.println("兴趣爱好:" + Arrays.asList(hobby));
    }
    

请求转发

请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发

Forwardrequests代码:

public class Forwardrequests extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求参数(办事的材料)查看
        String username = req.getParameter("username");
        System.out.println("在Forwardrequests(柜台1)中查看参数材料:"+username);
        //给材料盖章并传到Forwardrequests2(柜台2)去查看
        req.setAttribute("key","柜台1盖的章");
        //问路:Forwardrequests2(柜台2)怎么走
        /**
         *  /文件的工程目录,http://localhost:8080/工程目录
         */
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/req2");
        //走向Forwardrequests2(柜台2)
        requestDispatcher.forward(req,resp);
    }
}

Forwardrequests2代码:

public class Forwardrequests2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求参数(办事的材料)查看
        String username = req.getParameter("username");
        System.out.println("在Forwardrequests(柜台2)中查看参数材料:"+username);
        //查看是否有柜台1的盖章
        Object key = req.getAttribute("key");
        System.out.println("柜台1是否有章:"+key);
        //处理自己的业务
        System.out.println("柜台2处理自己的业务");
    }
}

结果:

在Forwardrequests(柜台1)中查看参数材料:说的是的是
在Forwardrequests(柜台2)中查看参数材料:说的是的是
柜台1是否有章:柜台1盖的章
柜台2处理自己的业务

base标签作用

base标签.png

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <base href="http://localhost:8080/servlet_request/a/b/c.html">
</head>
<body>
    <a href="../../index.html">跳转到首页</a>
</body>
</html>

HttpServletResponse类作用

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传 递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息, 我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置(给客户端发送信息)

两个输入流的说明

字节流getOutputStream()常用于下载(传递二进制数据)
字符流getWriter()常用于回传字符串(常用)

注意:两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错。

给客户端回传数据

给客户端回传字符串

public class HttpServletResponse1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();
        writer.write("response's content!!!");
    }
}

解决响应乱码问题

情景交际:

服务端(小明):我是个大帅比
客户端(小红):??????

很显然不赞同小明说的话并且表示疑问,因为没有进行贿赂(设置字符集)

方法一:

// 设置服务器字符集为 UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头,设置浏览器也使用 UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8")

方法二(推荐):

// 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");

请求重定向

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址。你去新地址访问。叫请求 重定向(因为之前的地址可能已经被废弃)

实现方法:

  • 方案一:

    //设置响应状态码302,表示重定向(搬迁)
    response.setStatus(302);
    //设置响应头,说明新地址位于哪里
    response.setHeader("location","http://localhost:8080/servlet_request/response2");
    
  • 方案二(推荐):

    response.sendRedirect("http://localhost:8080/servlet_request/response2");