HTTP协议&Request


HTTP协议

介绍

概念

超文本传输协议,是互联网上应用最为广泛的一种网络协议
简而言之:浏览器和服务器数据交换固定的格式

版本

http1.1:长连接,多个请求共用一个连接

分类

  1. 请求报文协议(浏览器发送给服务器的数据)
    1. 请求行
    2. 请求头
    3. 请求体
  2. 响应报文协议(服务器发送给浏览器的数据)
    1. 响应行
    2. 响应头
    3. 响应体

特点

  1. 先有请求
  2. 再有响应
  3. 一个请求对应一个响应

浏览器抓包观察请求报文协议

步骤

  1. 创建html页面
  2. 在html页面书写html代码
  3. 创建servlet
  4. 在servlet中书写java代码
  5. 启动服务器
  6. 打开浏览器,在浏览器访问页面,然后按F12,点击网络(network)
  7. 抓包结果分析

实现

  • html代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>GET请求</h2>
<form action="/getServlet" method="get">
    用户名:<input type="text" name="username" value="zhangsan" /><br>
    密码:<input type="text" name="pwd" value="123" /><br>
    <input type="submit" value="提交"/>
</form>


<h2>POST请求</h2>
<form action="/postServlet" method="post">
    用户名:<input type="text" name="username" value="zhangsan"/><br>
    密码:<input type="text" name="pwd" value="123"/><br>
    <input type="submit" value="提交"/>
</form>

</body>
</html>
  • java代码
package com.itheima.sh.d_http_04;

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

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("get....");
    }
}



package com.itheima.sh.d_http_04;

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

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("post....");
    }
}
  • 点击网络

Snipaste_2024-05-02_14-31-26.png

  • 抓包结果分析

请求报文协议.bmp

Request和Response概述

  1. service方法的两个参数request和response是由tomact创建的
  2. request表示请求数据,tomact将浏览器发送过来的请求数据解析并封装到request对象中
    1. servlet开发者可以通过request对象获得请求数据
  3. response表示响应数据,服务器发送给浏览器的数据
    1. servlet开发者可以通过response对象设置响应数据

request:获取请求数据

  • 浏览器会发送HTTP请求到后台服务器[Tomcat]
  • HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]
  • 后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
  • 所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数
  • 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务

response:设置响应数据

  • 业务处理完后,后台就需要给前端返回业务处理的结果即响应数据
  • 把响应数据封装到response对象中
  • 后台服务器[Tomcat]会解析response对象,按照[响应行+响应头+响应体]格式拼接结果
  • 浏览器最终解析结果,把内容展示在浏览器给用户浏览

初步体验:

@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用request对象 获取请求数据
        String name = request.getParameter("name");//url?name=zhangsan

        //使用response对象 设置响应数据
        response.setHeader("content-type","text/html;charset=utf-8");
        response.getWriter().write("<h1>"+name+",欢迎您!</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Post...");
    }
}

浏览器访问:
Snipaste_2024-05-02_15-30-40.png

Request对象

Request继承体系

Snipaste_2024-05-02_15-34-15.png
从java ee-api中可以查看到Servlet和HttpServletRequest两个都是接口,接口是无法创建对象的,那么service和doGet还有doPost方法中参数的对象是由谁创建的呢?
这个时候,我们就需要用到Request继承体系中的RequestFacade:

  • 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
  • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建
  • 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法

Request获取请求数据

HTTP请求数据总共分为三部分内容,分别是请求行,请求头,请求体

获取请求行数据

Snipaste_2024-05-02_15-42-54.png


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.获取请求方式: GET   String getMethod()
    System.out.println(request.getMethod());
    //2.获取虚拟目录(项目访问路径):  String getContextPath()  就是我们在tomcat配置的位置设置的路径,是虚拟的,就是随便定义
    //如果设置虚拟路径位置是/那么该方法获取的内容是空字符串
    System.out.println(request.getContextPath());//""
    //3.获取URL(统一资源定位符): http://localhost:8080/request-demo/req1
    //StringBuffer getRequestURL() 获取的是请求资源的绝对路径(含三要素)
    //StringBuilder 和  StringBuffer都表示字符串缓冲区,字符可以改变 。StringBuilder多线程不安全 效率高
    //StringBuffer多线程安全 效率低
    StringBuffer sb = request.getRequestURL();
    String s = sb.toString();
    //  http://localhost:8080/day16/requestRowDemo01Servlet
    System.out.println("s = " + s);
    //4.获取URI(统一资源标识符): /request-demo/req1
    //String getRequestURI() 获取的是请求资源的绝对路径(不含三要素)
    //  /day16/requestRowDemo01Servlet
    System.out.println(request.getRequestURI());
    //5.获取请求参数(GET方式): username=zhangsan&password=123  了解
    //String getQueryString()
    System.out.println(request.getQueryString());//"username=suoge&pwd=1234"
}


获取请求头数据

请求头的数据,格式为key:value
Snipaste_2024-05-02_16-01-18.png
所以可以根据请求头名称获取对应值的方法:
Snipaste_2024-05-02_16-01-48.png

获取请求体数据

浏览器在发送get请求的时候是没有请求体的,所以需要把请求方式变更为post
Snipaste_2024-05-03_10-03-20.png
获取请求体数据的方法:
1)ServletInputStream getInputStream()该方法可以获取字节和字符数据
2)BufferedReader getReader() 获取字符数据
:BufferedReader流是通过request对象来获取的,当请求完成后request对象就会被销毁,request对象被销毁后,BufferedReader流就会自动关闭,所以此处就不需要手动关闭流了。

获取请求参数(通用方式)

  1. 就是在获取之前获取请求方式,然后判断get还是post
  2. 通用方式,不需要判断请求方式(建议)

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/req4" method="get">
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="checkbox" name="hobby" value="1"> 游泳
    <input type="checkbox" name="hobby" value="2"> 爬山 <br>
    <input type="submit">

</form>
</body>
</html>

java代码:

package com.example.resquest;

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.Arrays;
import java.util.Map;
import java.util.function.BiConsumer;

@WebServlet("/req4")
public class RequestDemo4Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

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

        /*
            获取请求参数的通用方式:
                1.Map<String,String[]> getParameterMap() 获取所有的请求参数。
                    抓包冒号左边的作为map集合的key,冒号右边的值作为map集合的value
               2.String[] getParameterValues(String name) 获取指定的值。参数是抓包冒号左边的标识。获取的值放到数组中
               3.String getParameter(String name)获取指定的值。 参数是抓包冒号左边的标识
                    注意:如果参数的name有多个值谁在前面先获取谁

                    抓包结果:
                        username: zhangsan
                        password: 1234
                        hobby: 1
                        hobby: 2
         */

        //获取所有的请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //遍历所有的请求参数
        parameterMap.forEach((key,value)-> System.out.println(key+"---"+Arrays.toString(value)));

        //获取hobby的值
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("hobby:"+Arrays.toString(hobbies));

        //获取username的值
        String username = request.getParameter("username");
        System.out.println(username);
    }
}

jdk8遍历map集合

          map.forEach(new BiConsumer<String, String[]>() {
          @Override
          public void accept(String s, String[] strings) {
          }
      });
            BiConsumer中accept为抽象方法,就有一个,所以未函数式接口,能用lambda表达式简写

解决post请求乱码问题

解决思路

  1. 从tomact8开始以后,对于get请求乱码,tomact已经解决。对于post请求中文乱码没有解决,需要我们字节处理
  2. post请求乱码产生的原因和解决思路

Snipaste_2024-05-03_11-37-07.png
说明

  1. 页面使用的编码表是UTF-8编码,tomact使用的默认编码表ISO-8859-1进行解码,编码和解码使用的编码表不一样导致乱码
  2. 解决思路:先按照ISO-8859-1编码,再按照UTF-8进行重新解码

解决方案

方案一

 使用URLEncoder类进行编码:static String encode(String s, String enc)
                          参数:
                              s:编码的字符串
                              enc:使用编码表
 使用URLDecoder进行解码:static String decode(String s, String enc)
                          参数:
                              s:解码的字符串
                              enc:使用编码表

方案二

 使用String类中的方法进行编码:    byte[] getBytes(String charsetName)
                            参数表示指定的编码表,返回值表示编码后的字节数组
 使用String类中的构造方法进行解码:String(byte[] bytes, String charsetName)
                            参数:
                               bytes:字节数组
                               charsetName:表示指定的编码表
                              返回值:解码后的字符串

方案三

          如果是get请求,tomcat8底层已经帮助我们解决完了,我们只需要解决post乱码即可,但是上述
          两种方式对于post请求可以解决乱码,对于get请求本身获取到的已经是正确的数据,处理
          后又乱码了。
          我们的想法是:get请求不用我们自己书写代码处理乱码,只需要我们书写代码处理post乱码。
          我们接下来学习第三种解决方案:
          只解决来自于请求体数据的乱码。而get请求体没有数据,post请求体含有数据,所以我们可以理解为第三种处理方案只				
          是用来解决post乱码的。使用的api是ServletRequest接口中的:
              void setCharacterEncoding(String env)
                  参数:指定的编码表
          注意:该方式的代码必须书写在获取请求数据之前

Request请求转发(前后端分离后使用较少,面试考)

概述

一种在服务器内部的资源跳转方式
Snipaste_2024-05-03_13-13-17.png

  1. 浏览器发送请求给服务器,服务器中对应的资源A接受到请求
  2. 资源A处理完请求后将请求发给资源B
  3. 资源B处理完后将结果响应给浏览器
  4. 请求从资源A到资源B的过程就叫请求转发

实现方式

req.getRequestDispatcher(“资源B路径”).forward(req,resp);
说明:
1)获取这转发器:RequestDispatcher dispatcher = req.getRequestDispatcher(“资源B路径”);
2)转发:RequestDispatcher表示转发器,该接口中有一个方法:forward(request,response)

请求转发资源间共享数据:使用request域对象

  • 存储数据到request域[范围,数据是存储在request对象]中

void setAttribute(String name,Object o);

  • 根据key获取值

Object getAttribute(String name);

  • 根据key删除改键值对

void removeAttribute(String name);

请求转发特点

  1. 地址栏不会发生改变
  2. 可以共享request域对象数据
  3. 一次请求一次响应
  4. 属于服务器内部跳转行为

Request的生命周期

  1. 何时创建?

浏览器第一次访问tomcat服务器的时候

  1. 谁创建

tomact

  1. 创建对象做什么

浏览器第一次访问tomcat服务器的时候,tomcat创建request对象和response对象,传递给servlet中的service方法,然后我们可以在servlet中使用request对象调用方法获取请求数据(请求行 头 体),然后处理业务逻辑,处理完毕,然后tomcat将响应数据给浏览器,浏览器接收到响应之后,tomcat立刻销毁request和response对象。

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Zeal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值