HTTP协议详解+经典面试题

本文详细解读HTTP协议工作原理,重点比较GET和POST方法,讲解HTTP请求报头、状态码,并通过实例演示如何使用form表单、AJAX和JavaSocket构造HTTP请求,包括跨域问题和安全考量。
摘要由CSDN通过智能技术生成

✨HTTP协议详解+经典面试题


作者介绍:

🎓作者:偷偷敲代码的青花瓷🐱‍🚀
👀作者的Gitee:代码仓库
📌系列文章推荐:
计算机网络—网络原理之TCP/IP协议(一)
✨✨我和大家一样都是热爱编程✨,很高兴能在此和大家分享知识,希望在分享知识的同时,能和大家一起共同进步,取得好成绩🤳,今天和大家分享的章节是HTTP协议,如果有错误❌,欢迎指正哟😋,咋们废话不多说,跟紧步伐,开始学习吧~😊


在这里插入图片描述

HTTP协议

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

在这里插入图片描述

  • HTTP诞生与1991年,目前已经发展为最主流使用的一种应用层协议
  • HTTP往往是基于传输层TCP协议实现的(HTTP1.0, HTTP1.1, HTTP2.0 均为TCP, HTTP3 基于 UDP 实现)
  • 目前我们主要使用的还是 HTTP1.1 和 HTTP 2.0

HTTP 具体应用场景
我们平时打开一个网站,就是通过 HTTP 协议来传输数据的
在这里插入图片描述

当我们在浏览器中输入一个搜狗搜索的"网址"(URL)时,浏览器就给搜狗的服务器发送一个HTTP请求,搜狗的服务器返回一个HTTP响应.
这个响应结果被浏览器解析之后,就展示成我们看到的页面内容.(这个过程中浏览器可能会给服务器发送多个HTTP请求,服务器会对应返回多个响应,这些响应就包含了页面HTML,CCS,JavaScript,图片文字等信息)

所谓 “超文本” 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些
其他的资源, 比如图片, 视频, 音频等二进制的数据

理解"应用层协议"

我们已经学过 TCP/IP , 已经知道目前数据能从客户端进程经过路径选择跨网络传送到服务器端进程[ IP+Port ].
可是,仅仅把数据从 A 点 传送到 B点就完了吗?

这就好比,在淘宝上买了一部手机,卖家[ 客户端 ]把手机通过顺丰[ 传送+路径选择 ] 送到买家 [
服务器 ] 手里就完了吗?
当然不是,买家还要使用这款产品,还要在使用之后,给卖家打分评论。

所以,我们把数据从A端传送到B端, TCP/IP 解决的是顺丰的功能,而两端还要对数据进行加工处理或者使用,所以我们还需要一层协议不关心通信细节,关心应用细节!

这层协议叫做应用层协议。而应用是有不同的场景的,所以应用层协议是有不同种类的,其中经典协议之一的HTTP就是其中的佼佼者.

再回到我们刚刚说的买手机的例子,顺丰相当于 TCP/IP 的功能,那么买回来的手机都附带了说
明书【产品介绍,使用介绍,注意事项等】,而该说明书指导用户该如何使用手机【虽然我们都
不看,但是父母辈有部分是有看说明书的习惯的:)】,此时的说明书可以理解为用户层协议

理解HTTP协议的工作过程

当我们在浏览器中输入一个 “网址”, 此时浏览器就会给对应的服务器发送一个 HTTP 请求. 对方服务器收到这个请求之后, 经过计算处理, 就会返回一个 HTTP 响应.

在这里插入图片描述
事实上当我们访问一个网站的时候,可能涉及不止一次的HTTP 请求/响应 的交互过程.
可以通过 chrome 的开发者工具观察到这个详细的过程.

通过F12 打开 chrome 的开发者工具,切换到 Network 标签页,然后刷新页面即可看到如下图效果,每一条记录都是一次 HTTP 请求/响应

在这里插入图片描述
注意:

当前 搜狗主页 是通过 https 来进行通信的. https 是在 http 基础之上做了一个加密解密的工作, 后
面再介绍.

HTTP协议格式

HTTP 是一个文本格式的协议. 可以通过 Chrome 开发者工具或者 Fiddler 抓包, 分析 HTTP 请求/响应的细节.

抓包工具的使用

以 Fiddler 为例.下载地址
在这里插入图片描述

  • 左侧窗口显示了所有的 HTTP 请求/响应,可以选中某个请求查看详情
  • 右侧上方显示了 HTTP 请求的报文内容.(切换到 Raw 标签页可以看到详细的数据格式)
  • 右侧下方显示了 HTTP 响应的报文内容.(切换到 Raw 标签页可以看到详细的数据格式)
  • 请求和响应的详细数据,可以通过右下角的 view in Notepad 通过记事本打开

Fiddler 使用小技巧

可以使用 ctrl + a 全选左侧的抓包结果,按 delete 键清除所有被选中的结果

抓包工具的原理

Fiddler 相当于一个 “代理”

浏览器访问 sogou.com 时, 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给 sogou 的服务器. 当 sogou 服务器返回数据时, Fiddler 拿到返回数据, 再把数据交给浏览器.

因此 Fiddler 对于浏览器和 sogou 服务器之间交互的数据细节, 都是非常清楚的.
在这里插入图片描述

代理就可以简单理解为一个跑腿小弟. 你想买罐冰阔落, 又不想自己下楼去超市, 那么就可以把钱给
你的跑腿小弟, 跑腿小弟来到超市把钱给超市老板, 再把冰阔落拿回来交到你手上. 这个过程中, 这
个跑腿小弟对于 “你” 和 “超市老板” 之间的交易细节, 是非常清楚的^^

抓包结果

以下是一个 HTTP 请求/响应 的抓包结果.

在这里插入图片描述
HTTP 请求
在这里插入图片描述
HTTP 响应

在这里插入图片描述

协议格式总结

在这里插入图片描述
思考一个问题:为什么 HTTP 报文中要存在"空行"?

因为 HTTP 协议并没有规定报头部分的键值对有多少个. 空行就相当于是 "报头的结束标记", 或者
"报头和正文之间的分隔符".
HTTP 在传输层依赖 TCP 协议, TCP 是面向字节流的.如果没有这个空行, 就会出现 "粘包问题"

HTTP 请求(Request)

认识 URL

前言:

Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL(Uniform Resource Locator, 统一资源定位器)。它是www的统一资源定位标志,简单地说URL就是web地址,俗称“网址”。

URL
URL是对互联网上得到的资源的位置和访问方法的一种简洁表示,是互联网上标准资源的地址。URL它具有全球唯一性,正确的URL应该是可以通过浏览器打开此网页的,但如果您访问外网,会提示网页无法打开,这并不能说明这个URL是错误的。只不过在国内不能访问而已。

下面以浏览一组网页来说URL,如下图:
在这里插入图片描述

https://blog.csdn.net/Biteht?spm=1010.2135.3001.5421

以上是我CSDN博客的URL地址。访问百度网站时,你的浏览器上就会显示:http//www.baidu.com,如下图
在这里插入图片描述

URL 基本格式

在这里插入图片描述

URL小结:
对于URL 来说,里面的结构看起来复杂,其实最重要的,和开发关系紧密的,就四个部分:

  1. ip 地址/域名
  2. 端口号(经常是小透明)
  3. 带层次结构的路径
  4. query string 查询字符串
关于 URL encode/decode

当 query string 中如果包含了特殊字符,就需要对特殊字符进行转义(url encode)

转义过程叫做 url encode
转义后的内容还回来 url decode

url 里面是有很多特殊含义符号的

/ : & = ... 这些符号都是在 URL 中具有特定含义的~

注意:如果,query string 里也包含了这类特殊符号,就可能导致 URL 被解析失败

比如:当我们在sogou 中搜索 C++ 的时候,就可以看到,URL中的 query string 里面有一个键值对,就表示了查询词内容
在这里插入图片描述
这里的%2B是在骂人吗?显然不是!!!%2B 其实就是 通过 url encode 转义得到的结果

认识"方法"(method)

HTTP协议的方法非常多!但是最常用的,也就是 GET 和 POST
在这里插入图片描述

HTTP 中引入这些方法的初衷是为了表示不同的"语义"(语义:是否有特定的含义)
比如在 HTML 里,h3,p,a,img... 语义化标签 div span 无语义标签

1.GET 方法

GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源

使用 Fiddler 观察 GET 请求:
打开 Fiddler,访问 搜狗主页,观察抓包结果
在这里插入图片描述
在上面的结果中可以看到:最上面的 在这里插入图片描述
是通过浏览器地址栏发送的 GET 请求.选中它并观察请求的详细结果:

在这里插入图片描述

GET 请求的特点:

  • 首行的第一部分为 GET
  • URL 的 query string 可以为空,也可以不为空
  • header 部分有若干个键值对结构
  • body 部分为空
2.POST 方法

POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面).

使用 Fiddler 观察 POST 方法
在Gitee登陆页面, 输入用户名, 密码, 验证码之后, 点击登陆, 就可以看到 POST 请求.
在这里插入图片描述
查看它的具体请求:

在这里插入图片描述

POST 请求的特点:

  • 首行第一部分为 POST
  • URL 的 query string 一般为空(也可以不为空)
  • header 部分有若干个键值对结构
    body 部分一般不为空,body 内的数据格式通过 header 中的 content -Type 指定 body 的长度由 header 中的 content-Length 指定
3.其他方法
  • PUT 与 POST 相似,只是具有幂等特性,一般用于更新
  • DELETE 删除服务器指定资源
  • OPTIONS 返回服务器所支持的请求方法
  • HEAD 类似于GET,只不过响应体不返回,只返回响应头
  • TRACE 回显服务器端收到的请求,测试的时候会用到这个
  • CONNECT 预留,暂无使用
经典面试题:谈谈 GET 和 POST 的区别

当面试官问到 GET 和 POST 的区别时:
第一句话,先盖棺定论!!GET 和 POST 没有本质区别!!(具体来说,相当于是 GET 能使用的场景,也能天成POST,POST 使用的场景,也能替换成 GET),但是在细节上还是有一些区别

  1. 语义上的区别:GET 通常用来读取数据 POST 通常用来上传数据
    现状是 GET 也经常用来上传数据,POST用来读取数据
  2. 通常情况下,GET 是有没有 body,GET 通过 query string 向服务器传递数据
    通常情况下, POST 是有 body,POST 通过 body 向服务器传递数据,但是 POST 没有 query string
    注意:如果我就想让 GET 有 body(自己构造一个带 body的 GET请求)或者就想让 POST 带有 query sting 是完全可以的
  3. GET 请求一般是幂等的,POST 请求一般是不幂等的(也不是强制要求,而是建议)
    幂等:每次你相同的输入,得到的输出结果是确定的
    不幂等:每次你相同的输`,得到的结果是不确定的
  4. GET 可以被缓存,POST 不能被缓存(提前把结果记住,如果是幂等的,记住结果是很有用的,节省了下次访问的开销,如果不是幂等的,就不应该去记)

认识请求"报头"(header)

header 的整体的格式也是 "键值对"结构,每个键值对占一行,看个值之间使用分号分割

Host

表示服务器主机的地址和端口

在这里插入图片描述

Content-Length/ Content-Type

Content-Length:表示 body中的数据长度
Content-Type:表示 请求的 body 中的 数据格式

注意:这两个属性是在描述 body,如果你的请求里就没有 body(GET),也就不需要这两个字段了

一般POST都是带body,一般登录系统都是基于 POST 来实现的,我们抓个包具体来观察一下:
在这里插入图片描述
点击:在这里插入图片描述
我们可以看到:
在这里插入图片描述
这里注意有两个问题:
1.为什么登录系统是使用POST实现?使用GET能不能实现登录呢

使用 GET 是完全可以实现登录的

2.为什么还主要使用 POST 呢?

登录肯定就会给服务器 传递用户和密码,如果是 GET,用户名密码习惯上就会放到 URL 的 query string 中来传递(此时浏览器的地址栏里的路径,就可能变的很长一串)这个时候用户体验可能就不太好

网上有种说法:使用 POST 实现登录,是因为 POST 比 GET 更安全

对于这个说法是大错特错的,安不安全取决于你的数据是否明文传输,是否是加密过的

第三种最常见请求中的 body 的格式:json

body格式如下:
在这里插入图片描述

关于 Content-Length 的补充

HTTP 也是基于 TCP 的协议,TCP 是一个面向字节流的协议,粘包问题 ==> 合理设计应用层协议,来明确 包和包 之间的边界:

  1. 使用分隔符
  2. 使用长度

在这里插入图片描述

User-Agent(简称 UA)

表示的是,当前用户是在拿一个啥样的东西来上网

在这里插入图片描述

Referer

表示了当前的页面,是从哪个页面,跳转过来的

在这里插入图片描述

注意:Referer 不一定是有的,如果你是通过浏览器地址栏直接输入 地址,或者直接点收藏夹,这个时候是没 referer 的

Cookie

Cookie 就是浏览器给页面提供的一种 能够持久化存储数据的机制

持久化指的是:数据不会因为程序重启或者主机重启,而丢失(写到磁盘里)

Cookie 具体的组织形式:

  1. 先按照域名来组织,针对每个域名,分别分配一个小房间
    就好比如:我访问搜狗,浏览器就会给 sogou 这个域名记录一组cookie,我访问码云,浏览器也就会给 码云一组 cookie
  2. 一个小房间里面,又会按照 键值对 的方式来组织数据

在这里插入图片描述

Cookie 数据从哪里来的?

其实是服务器返回给客户端的

下图为抓包实例:
在这里插入图片描述
在这里插入图片描述
再举个通俗易懂的例子方便我们对 Cookie 的理解:


虽然就诊卡上面可以存储一些信息,但是保存的数量是有限的,真正保存我的这心信息,并不是这个卡,而是放到医院的服务器上,而卡上,只需要存储我的一个身份标识(存储一个用户id),这些关键信息,存储在服务器上,管这个东西称为 "session"会话

关于 Session 会话的理解:
在这里插入图片描述
总结:

  • Cookie 是浏览器提供的一个持久化存储数据的机制
  • Cookie 的最重要应用场景,就是存储会话 id,进一步的让访问服务器的后续页面的时候,能够带上这个id从而让服务器能够知道当前用户信息(服务器上保存用户信息这样的机制就称为 Session 会话)
  • Cookie 能不能用来存储别的信息,当然是可以的,具体想存啥就存啥,都是程序猿自定义的

HTTP 响应详解

认识"状态码"(status code)

状态码表示访问一个页面的结果(是访问成功,还是失败,还是其他的一些情况)

200 OK

这是一个最常见的状态码,表示访问成功

404 Not Found

要访问的资源不存在

在这里插入图片描述

403 Forbidden

虽然资源有,但是没有权限使用

在这里插入图片描述

405 Method Not Allowed

这个情况,你去外面的网站上抓包,很难遇到…
但是如果后面自己写网站后台,这个就很容易出现

例如:尝试使用 GET 来访问人家的服务器,但是可能人家只支持 POST,于是就返回405

500 Internal Server Error

服务器自己出问题了,意味着出现 bug,外面的服务器上看到这种情况的概率也是比较低的
但是我们后面自己写代码,也是容易出现这种情况

504 Gateway Timeout

服务器太忙了

302 Move temporarily

在登录过程中,非常典型的情况
重定向:这个词在计算机的很多常见中都会涉及到,不仅仅是 HTTP,但是虽然在不同场景中细节有差异,但是表示的核心含义,都是呼叫转移

比如呼叫转移–>中国移动,运营商这里可以办理一个业务,有人拨打我的旧号码,就会自动的 转接到 我的新号码上

在重定向响应中,一般都是需要 Location 属性的
在这里插入图片描述

总结:

上面就介绍了 最常见的一些状态码,但是实际上 HTTP 状态码,种类非常多!

在这里插入图片描述

通过 form 表单构造 HTTP 请求

form(表单)是HTML中的一个常用标签,可以用于给服务器发送 GET 或者 POST 请求
注意:切勿把 form 拼写成 from!

form发送GET请求

form 的重要参数:

  • action:构造的 HTTP 请求 的 URL 是什么
  • method:构造的 HTTP 请求的 方法是 GET 还是 POST(form 只支持 GET 和 POST)

input 的重要参数:

  • type:表示输入框的类型.text表示文本,password表示密码,submit 表示提交按钮
  • name:表示构造出的 HTTP 请求的 query string 的key. query string 的 value 就是输入框的用户输入的内容
  • value:input 标签的值.对于 type 为 submit 类型来说,value 就对应了按钮上显示的文本

下列为具体代码实现以及图解:

<form action="https://www.sogou.com/index.html" method="get">

        <input type="text" name="username">
        <input type="text" name="password">
        <input type="submit" value="提交">

    </form>

在这里插入图片描述
在这里插入图片描述
当我们在输入框输入内容点击提交的时候页面会跳转到我们之前 action 指定的 URL
在这里插入图片描述

在这里插入图片描述

form发送POST请求

使用 form 发送 POST 请求 和 使用 form 发送 GET 请求步骤一样,我们只需要将 method = "GET" 换成 method = "POST"
在这里插入图片描述

通过 ajax构造HTTP请求

在学习 ajax 之前,我们先了解一下,为什么要使用它?

form表单这种方式,是一个更加原始的构造方法,使用 form 一定会涉及到"页面跳转",浏览器需要加载出一个全新页面,这个事情就是非常不科学的了,尤其是页面非常复杂的时候~
随着前端页面越来越复杂,就希望,能够让页面不去整个全部加载,而是只加载其中需要变化的某个小部分,这个情况,就可以使用 ajax

ajax 全称 Asynchronous Javascript And XML

ajxa 属于 基于异步等待的方式来进行的,下面给大家 弄清楚几个 概念

在这里插入图片描述

发送 GET 请求

在发送 GET 请求之前 先引入 jquery

  1. 现在搜索引擎中搜索 jquery cdn 查询词
  2. 在结果中,找到一个 合适的 cdn 的 url
  3. 打开对应的 url,加载出 jquery 本体
  4. 复制粘贴内容到本地文件

下面为具体代码以及图解:

 <script src="jquery.js"></script>

    <script>
        $.ajax({
            type:'get',
            url:'http://www.sogou.com/index.html',
            success:function(boby){
                //success 对应一个回调函数
                //这个函数就会在正确获取到 HTTP 响应之后,来调用
                //"异步"
                //回调函数的参数,就是HTTP响应的 boby 部分
                console.log("获取到响应数据! " + boby);
            },
            error:function() {
                //error 也对应一个回调函数
                //这个函数也会在请求失败之后触发
                //"异步"
                console.log("获取请求失败!");

            }

        });
    </script>

在这里插入图片描述
当我们运行我们的网站的时候,会发现报错:
在这里插入图片描述

通过刚才 ajax 的请求,我们抓包看到,响应里面 是200OK,并且 body也是 html数据
在这里插入图片描述
但是浏览器仍然认为这是一个"出错"的请求

在这里插入图片描述
为什么会出现报错呢?

出现这个报错的原因,是浏览器禁止 ajax 进行 跨域访问(跨越多个域名/多个服务器)

当前 页面所处在的服务器,是本地文件
页面中 ajax 请求的URL 域名是 www.sougou.com
这样就触发了 跨域操作

什么样才不算是跨域呢?

当前页面所在的服务器,就是在 www.sogou.com中
页面中再通过ajax,请求 URL,域名为 www.sogou.com 这种就不算跨域

发送 POST 请求

发送 POST 请求方法和代码同上,只是将 type:'get' 改为 'post'即可,这里不再具体演示
在这里插入图片描述

通过 Java socket 构造 HTTP 请求

java 构造一个 HTTP 请求,主要就是基于 TCP socket,按照 HTTP 请求的报文格式,构造出一个匹配的字符串,再写入 socket 即可
在实际研发过程中,确实也会有一些基于 java构造 http请求的情况,可以直接使用第三方库来实现,不一定非得要直接使用scoket

具体就演示了~

代码如下:

public class HttpClient {
    private Socket socket;
    private String ip;
    private int port;
    public HttpClient(String ip, int port) throws IOException {
        this.ip = ip;
        this.port = port;
        socket = new Socket(ip, port);
   }
    public String get(String url) throws IOException {
        StringBuilder request = new StringBuilder();
        // 构造首行
        request.append("GET " + url + " HTTP/1.1\n");
        // 构造 header
        request.append("Host: " + ip + ":" + port + "\n");
        // 构造 空行
        request.append("\n");
        // 发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(request.toString().getBytes());
        // 读取响应数据
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024 * 1024];
        int n = inputStream.read(buffer);
        return new String(buffer, 0, n, "utf-8");
   }
    public String post(String url, String body) throws IOException {
        StringBuilder request = new StringBuilder();
        // 构造首行
        request.append("POST " + url + " HTTP/1.1\n");
        // 构造 header
        request.append("Host: " + ip + ":" + port + "\n");
               request.append("Content-Length: " + body.getBytes().length + "\n");
        request.append("Content-Type: text/plain\n");
        // 构造 空行
        request.append("\n");
        // 构造 body
        request.append(body);
        // 发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(request.toString().getBytes());
        // 读取响应数据
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024 * 1024];
        int n = inputStream.read(buffer);
        return new String(buffer, 0, n, "utf-8");
   }
    public static void main(String[] args) throws IOException {
        HttpClient httpClient = new HttpClient("42.192.83.143", 8080);
        String getResp = httpClient.get("/AjaxMockServer/info");
        System.out.println(getResp);
        String postResp = httpClient.post("/AjaxMockServer/info", "this is 
body");
        System.out.println(postResp);
   }
}

总结

“种一颗树最好的是十年前,其次就是现在”
所以,
“让我们一起努力吧,去奔赴更高更远的山海”

如果有错误❌,欢迎指正哟😋

🎉如果觉得收获满满,可以动动小手,点点赞👍,支持一下哟🎉
在这里插入图片描述

  • 65
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 80
    评论
评论 80
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

偷偷敲代码的青花瓷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值