前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【计网】HTTP协议详解

【计网】HTTP协议详解

作者头像
用户11029129
发布2024-12-13 08:32:19
发布2024-12-13 08:32:19
15000
代码可运行
举报
文章被收录于专栏:编程学习编程学习
运行总次数:0
代码可运行

🚀认识HTTP协议

  虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用。HTTP(超文本传输协议) 就是其中之一。

  在互联网世界中,HTTPHyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。听起来好像是那么回事,实际上超文本传输协议指的是不仅仅可以传输文本,还可以传输图片、音频、视频等文件。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。

  HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个 无连接、无状态 的协议,即 每次请求都需要建立新的连接,且 服务器不会保存客户端的状态信息


🚩认识URL

  我们常说的“网址”,其实就是 URLUniform Resource Locator),一个网址通常包含如下部分:

  我们从网络上获取的文字,图片,音视频等等,这些信息本质上都是资源。那么在我们获取这些信息之前,这些文件存储在哪个位置?大多数在Linux服务器中,而在Linux当中,一切皆文件,所以 网络上获取的所有资源本质上都是文件!

  而我们从网络中获取数据本质上就是从 Linux服务器当中获取文件,而每个文件都是有路径的,所以找到一个文件直接通过文件路径即可访问资源。而我们能够找到对应文件的 前提是我们能够找到对应的服务器。 而要想 找到一个服务器就必须要知道该服务器的 IP[ + PORT]而IP[PORT] + 服务器中的文件路径 也就在网络中标识了唯一的文件(资源)

  这里IP后面为什么要给PORT打上括号呢?原因其实在前面文章中也说过,客户端在像服务器端发起请求时,虽然需要绑定IP和端口号,但是不需要用户来绑定,因为这一步操作系统会给你自动绑定,所以在客户端看来,我只需要知道服务器的IP即可。不同于自定义应用层协议,可以随便绑定端口号,这些成熟的上层协议的端口号一般都是固定的,比如http协议的端口号就是 80。

  在最上方那张图当中,有一点过时了,实际上现在登录信息时,是不需要用户身份信息验证的。并且片段标识符早期可以将图片进行轮播所用,但是现在运用的同样少了,所以这张图实际上应该如下所示:

  当我们在某度的搜索框内搜索东西的时候,比如我们搜索C++,浏览器将在资源路径后面出现一个 wd=关键字信息(不同的浏览器解释可能不同,有些浏览器就不会使用wd),如果你仔细观察,其实wd后面跟着的就是我们想要索引的关键字。而这些关键字有时候会发现跟我们在搜索框内搜索的不同:

  我们在随便搜索一个问题时,我们会在资源路径后面看到一大堆的字符串,其中包含不少的特殊字符,比如 ‘?’,‘/’, ‘:’ 等字符,而 这些字符实际上有特殊含义的,已经被 url 当做特殊意义理解了。因此这些字符不能随意出现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。

  由上面的例子我们可以看出,其实浏览器对特殊字符的转换是有规则的,而这个规则就是:将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位做一位,前面加上%,编码成%XY 格式

  如果你对我们输入中文出来的关键字也是被转换为16进制数而感到疑惑,那么你就不懂ASCII表的含义,所谓的语言本质就是符号,所以语言,ASCII本质就是一个数据数字和符号映射关系的表。我们知道计算机无法对语言进行处理,所以必须要将文字进行转换才能让计算机识别。


🚀Http协议请求与响应格式

  我们构建一个Tcp服务器,上层调用服务内部仅仅将将来从客户端发来的请求字符串打印出来,其他什么事情也不做,启动tcp服务器,我们以浏览器为客户端,如果今天浏览器作为客户端,向我们的服务器发起请求,端口号使用自定义端口号。由于客户端是浏览器,所以我们不需要序列化和反序列化工作,因为浏览器已经将这个工作给做了。

  如果我们使用浏览器发送了请求,并且服务器端收到了请求,那么我们就可以看到以下返回的客户端请求格式,Tcp上层调用的服务代码如下,我们只对请求进行打印:

代码语言:javascript
代码运行次数:0
复制
#include <string>
#include <iostream>

class HttpServer
{
public:
    HttpServer(){}
    std::string HandlerHttpRequest(std::string req)
    {
        std::cout << "-------------------------------" << std::endl;
        std::cout << req;

        return std::string();
    }
    ~HttpServer(){}
private:
};

  我们可以发现,客户端发来的请求报头一共有11行,其中最后一行为空行,但实际上它们就只有一行,只不过每一行的末尾都有 \r\n将它们连接到一起。我们之前说过,无论是什么协议,都要做到 将报头 和 有效载荷进行分离,同样,http协议也是如此。

  在上图中,空行以上实际上全部都是有效载荷的部分,空行之后就是正文,只不过这里我们没有做任何处理,所以空行下面就啥也没有。


🚩HTTP Request

  上面我们已经展示了什么是http的请求报文的报头部分,不过上面的仅仅是具体的一些字符串,这HTTP的请求的格式如下图所示:

  除此之外,http响应格式不同于其他的响应,我们可以看到第一行的请求行当中实际包含了 请求方法,URL,HTTP版本(客户端版本) 这些信息,我们具体来看一看一个Request的报头第一行内容:

  • 首行: [方法] + [url] + [版本]
  • Header : 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body : 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度

  为什么这里我们只有协议的处理方法与协议的版本信息呢?因为我们写的程序并没有向服务器发起任何的资源访问,所以这里 访问的资源路径默认为 ‘/’ 。而剩下的所有行,也都符合上图中的 Key: Value 的形式,而我们要学习的就是HTTP请求报文中的请求行以及请求报头信息。

  我们知道,任何协议都需要有将 报头 和 有效载荷进行分离的能力,那么HTTP协议是根据什么对报头和载荷进行分离的呢?我们发现http请求格式中,报头部分与正文部分实际上是有一个空行作为分隔的,所以 HTTP协议就可以通过空行(“\n”)来分离报头和有效载荷部分

  在http请求报头当中,存在一个 key为 Content-Length value为 正文长度 的key: value请求行,如果发送的请求当中没有正文,那么这个字段也就不会存在。


🚩HTTP Response

  除了发送请求的报文有格式以外,服务器对客户端返回的报头应该也要有响应,那么也就会存在与请求格式大差不差的响应格式:

  在状态行当中,包含了HTTP版本(服务端版本),状态码,状态码描述三个字段,其中这里的版本与发送请求的版本不同,这里使用的是服务端的http版本,而状态码我们是非常常见的,比如 404,403… 而状态描述就是指对状态码的描述,比如:404,状态描述就是 Not Found。下图是一个简单的http应答报文:

  • 首行: [版本号] + [状态码] + [状态码解释]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度; 如果服务器返回了一个 html 页面, 那么 html 页面内容就是在 body 中

  为什么http请求和应答当中都必须要有http版本这个字段信息呢?这是因为双方需要确定对方的http的版本信息,以便于使用相同或者近似的协议处理方法去做请求处理与响应。

微信就是一个很好的例子,我们常用手机都会知道,微信每隔一段时间就会更新一次。其实微信每次更新都是小范围的更新,如果没什么问题就逐渐扩大范围,直到达到一定的基数才会实现全部用户进行更新,如果已经更新的用户和没有更新的用户发消息,如果因为版本不同而发不了消息了,这是客户最不愿看到的情况

所以微信服务器必须有对应老版本信息的处理方法,如果一个老版本的用户向新版本用户发送了信息,就会先检测用户版本信息,如果为老版本,就选择来版本的处理方法来相互通信,这样就能保证不同版本之间可行的通信


🚩HTTP常见Header
  • Content-Type: 数据类型(text/html 等)

  Content-Type表示资源的数据类型,资源类型必须得提前在代码当中定义好,如果你拿着一个js文件返回给浏览器,但是却告诉浏览器这个文件是html文件,这就可能会导致一些无法预测的问题,不过浏览器还是很聪明的,如果你发来的是js文件,那么浏览器不会解释为html文件的,但是文件类型有非常多,浏览器不能保证每次都能帮你纠正错误,在服务器的代码中,我们有必要将文件后缀做解析,发送正确的文件后缀,至于如何做,我们可以使用 Content-Type对照表 来定位文件类型:

  • Content-Length: Body 的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上
  • User-Agent: 声明 用户的操作系统 和 浏览器版本信息
  • referer: 当前页面是从哪个页面跳转过来的
  • Location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能

  再发送报文或者相应报文的报头当中,都在一个叫做 Connection 的字段,HTTP 中的 Connection 字段是 HTTP 报文头的一部分,它主要 用于控制和管理客户端与服务器之间的连接状态

核心作用

管理持久连接:Connection 字段还用于管理持久连接(也称为长连接)。持久连接允许客户端和服务器在请求/响应完成后不立即关闭 TCP 连接,以便在同一个连接上发送多个请求和接收多个响应。

持久连接(长连接): HTTP/1.1在 HTTP/1.1 协议中,默认使用持久连接。当客户端和服务器都不明确指定关闭连接时,连接将保持打开状态,以便后续的请求和响应可以复用同一个连接HTTP/1.0在 HTTP/1.0 协议中,默认连接是非持久的。如果希望在 HTTP/1.0上实现持久连接,需要在请求头中显式设置 Connection: keep-alive

语法格式

  • Connection: keep-alive表示希望保持连接以复用 TCP 连接
  • Connection: close表示请求/响应完成后,应该关闭 TCP 连接

HTTP常见Header表

字段名

含义

Accept

客户端可接受的响应内容类型

Accept- Encoding

客户端支持的数据压缩格式

Accept- Language

客户端可接受的语言类型

Host

请求的主机名和端口号

User-Agent

客户端的软件环境信息

Cookie

客户端发送给服务器的 HTTPcookie 信息

Referer

请求的来源 URL

Content-Type

实体主体的媒体类型

Content-Length

实体主体的字节大小

Authorization

认证信息,如用户名和密码

Cache-Control

缓存控制指令

Connection

请求完后是关闭还是保持连接

Date

请求或响应的日期和时间

Location

重定向的目标URL(与 3xx 状态码配合使用)

Server

服务器类型

Last-Modified

资源的最后修改时间

ETag

资源的唯一标识符,用于缓存

Expires

响应过期的日期和时间


🚩URI资源以及网页跳转原因

  URI是客户端访问服务器的资源路径,当服务器端收到客户端发来的请求时,如果没有访问任何资源路径,那么默认就是 ‘/’ ,而默认的’/’ 需要有一个默认的首页,以后只要对服务器进行访问,如果没有访问具体的服务器资源,就会默认跳转到给出的默认首页,通常默认首页是一个 index.html/index.htm 文件。而这些文件,通常存在于一个名为 wwwroot 的目录结构下,服务器默认访问资源路径实际上就是wwwroot目录下的 index.html文件。

  当然,wwwroot是一个主目录,其中将来可以存在多个子目录,而每个目录都应该有一个默认的首页,比如我们使用 telnet 具体网址 访问协议,命令来请求百度的默认首页内容:

  网页页面之间跳转的功能,是通过链接来进行切换页面的,如下图:

  当然不仅仅如此,我们在页面中访问网页,进行页面跳转,就是每一次http请求:

  什么是网站?站在我们程序员的角度来说,网站其实就是一堆特定的目录和文件所构成的目录结构!前端程序员并不需要管后端的各种服务是怎么实现的,只需要将wwwroot里的内容做好,进行页面之间的跳转即可。


🚀HTTP其他属性字段

🚩HTTP状态码

  我们通过HTTP访问服务器上的资源时,并不是每一都会访问成功,往往面临着多种特殊情况,对于这些特殊情况,被分类为了一下五类状态描述:

  最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)。以下是常见状态码表:

状态码

含义

应用样例

100

Continue

上传大文件时,服务器告诉客户端可以继续上传

200

OK

访问网站首页,服务器返回网页内容

201

Created

发布新文章,服务器返回文章创建成功的信息

204

No Content

删除文章后,服务器返回“无内容”表示操作成功

301

Moved Permanently

网站换域名后,自动跳转到新域名;搜索引擎更新网站链接时使用

302

Found or See Other

用户登录成功后,重定向到用户首页

304

Not Modified

浏览器缓存机制,对未修改的资源返回304 状态码

400

Bad Request

填写表单时,格式不正确导致提交失败

401

Unauthorized

访问需要登录的页面时,未登录或认证失败

403

Forbidden

尝试访问你没有权限查看的页面

404

Not Found

访问不存在的网页链接

500

Internal Server Error

服务器崩溃或数据库错误导致页面无法加载

502

Bad GateWay

使用代理服务器时,代理服务器无法从上游服务器获取有效响应

503

Service Unavaiable

服务器维护或过载,暂时无法处理请求

  有关重定向,很多人对此感到陌生,实际上,在我们日常生活当中重定向也是非常常见的,比如我们在观看某讯视频时,看了几分钟之后,就会自动弹出一个页面,让你充值会员。这其实就是一种重定向,以及301永久重定向,有些网站的域名可能换了,但是很多用户还是习惯使用老域名,为了避免这部分用户的流失,所以会对原域名做一个重定向,到新的域名访问资源。

  5开头的状态码大家很少见,因为5开头的状态码表示服务器端出现了问题,实际上,就算是服务器端出现了错误,很可能也会被设置为4xx的状态码,也就是转化为客户端错误,如果用户每次访问服务器端都弹出5xx,服务器哪哪发生错误,这绝对会让部分用户不满意,所以很多时候我们并不能看到5xx的状态码,不过这也就能骗一骗外行人了。

  以下是仅仅包含重定向相关状态的表格:

状态码

含义

是否为临时重定向

应用样例

301

Moved Permanently

否(永久重定向)

网站换域名后,自动跳转到新域名;搜索引擎更新网站链接时使用

302

Found 或 SeeOther

是(临时重定向)

用户登录成功后,重定向到用户首页

307

Temporary Redirect

是(临时重定向)

临时重定向资源到新的位置(较少使用)

308

Permanent Redirect

否(永久重定向)

永久重定向资源到新的位置(较少使用)

HTTP 状态码 301(永久重定向)和 302(临时重定向)都依赖 Location 选项。以下是关于两者依赖 Location 选项的详细说明

HTTP 状态码 301(永久重定向)

  • 当服务器返回 HTTP 301 状态码时,表示请求的资源已经被永久移动到新的位置。
  • 在这种情况下,服务器会在响应中添加一个 Location 头部,用于指定资源的新位置。这个 Location头部包含了新的 URL 地址,浏览器会自动重定向到该地址。
  • 例如,在 HTTP 响应中,可能会看到类似于以下的头部信息: HTTP/1.1 301 Moved Permanently\r\n Location: https://www.new-url.com\r\n

HTTP 状态码 302(临时重定向):

  • 当服务器返回 HTTP 302 状态码时,表示请求的资源临时被移动到新的位置。
  • 同样地,服务器也会在响应中添加一个 Location 头部来指定资源的新位置。浏览器会暂时使用新的 URL 进行后续的请求,但不会缓存这个重定向。
  • 例如,在 HTTP 响应中,可能会看到类似于以下的头部信息: HTTP/1.1 302 Found\r\n Location: https://www.new-url.com\r\n

总结

无论是 HTTP 301 还是 HTTP 302 重定向,都需要依赖 Location 选项来指定资源的新位置。这个 Location 选项是一个标准的 HTTP 响应头部,用于告诉浏览器应该将请求重定向到哪个新的 URL 地址


🚩HTTP 的常见方法

  HTTP协议存在许多方法,比如获取服务器资源使用GET方法,向服务器发送数据使用POST方法,实际上GET方法也可以提交数据给服务器,只不过跟POST方法有些差别,我们来具体了解一下这些方法:

GET 方法

  • 用途用于请求 URL 指定的资源
  • 示例GET /index.html HTTP/1.1
  • 特性指定资源经服务器端解析后返回响应内容

POST 方法

  • 用途用于传输实体的主体,通常用于提交表单数据
  • 示例POST /submit.cgi HTTP/1.1
  • 特性可以发送大量的数据给服务器,并且数据包含在请求体中

PUT 方法(不常用)

  • 用途:用于传输文件,将请求报文主体中的文件保存到请求 URL 指定的位置。
  • 示例:PUT /example.html HTTP/1.1
  • 特性:不太常用,但在某些情况下,如 RESTful API 中,用于更新资源。

HEAD 方法

  • 用途:与 GET 方法类似,但不返回报文主体部分,仅返回响应头。
  • 示例:HEAD /index.html HTTP/1.1
  • 特性:用于确认 URL 的有效性及资源更新的日期时间等。

DELETE 方法(不常用)

  • 用途:用于删除文件,是 PUT 的相反方法。
  • 示例:DELETE /example.html HTTP/1.1
  • 特性:按请求 URL 删除指定的资源。

OPTIONS 方法

  • 用途:用于查询针对请求 URL 指定的资源支持的方法。
  • 示例:OPTIONS * HTTP/1.1
  • 特性:返回允许的方法,如 GET、POST 等。

  以上这些方法一般都不是由后端代码来完成的,不过如果想要处理这些请求后端也可以处理,一般这些都属于前端页面的请求方法,我们可以通过 HTML表单 来获取简单的前段页面,而以上方法中最重要的莫过于 GET 和 POST方法了。

  其中GET方法我们如何理解呢?就拿简单的登录页面来说,我们登录页面实际上在前端代码中,就是一个form表单:

  我们可以看到在搜索框内出现的网址,在前端页面上我们指定了要上传资源的路径,以及使用方法,在网址中,我们看到除了前端页面以外,后面紧跟着的字符是 “?” ,问号后面跟着的起始就是用户的用户名信息,以及用户的密码信息。所以由此我们就可以看到,使用HTTP协议实际上是不安全的,所以催生出了HTTPS协议(下期再谈),更加注重用户的隐私性。

  以上是GET上传资源的方式,是通过url来上传资源的。而POST方法上传参数,是以正文形式进行参数上传的, content-length + request body,有人会说,POST比GET更安全,更加保护用户的信息,因为我们在浏览器的网址上看不到,我要说的是,GET和POST都不安全!因为POST方法虽然在浏览器层面看不到用户信息,但是如果你会抓包,实际上所有的用户信息都会被暴漏出去,所以这两种方法都不能称为安全方法。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🚀认识HTTP协议
    • 🚩认识URL
  • 🚀Http协议请求与响应格式
    • 🚩HTTP Request
    • 🚩HTTP Response
    • 🚩HTTP常见Header
    • 🚩URI资源以及网页跳转原因
  • 🚀HTTP其他属性字段
    • 🚩HTTP状态码
    • 🚩HTTP 的常见方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档