【网络】HTTP协议详解

这篇具有很好参考价值的文章主要介绍了【网络】HTTP协议详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!💪💪💪

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

📙前言


哟,大家好,我是白晨。距离上一次更新已经过了一段时间了,属实是当鸽子当惯了🤣。

上一篇文章我们全面讲解了网络中的基础知识(没看过上篇文章的的可以先去看上一篇文章【网络】网络基础知识详解),这篇文章白晨准备从应用层中的一个及其重要的协议开始讲起,它就是——HTTP协议。HTTP协议由于简单、快速而成为了应用最广泛的web文档传递协议协议,在理解了HTTP协议的种种行为后,再自顶向下去学习传输层,网络层以及数据链路层将会好理解许多。


📗HTTP协议


🏡1. HTTP背景介绍


1989 年 3 月,HTTP 诞生。最初设想的基本理念是: 借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的 WWW( World Wide Web,万维网)。现在已提出了 3 项 WWW 构建技术,分别是:

  • 把 SGML(StandardGeneralized Markup Language,标准通用标记语言)作为页面的文本标记语言的 HTML(HyperText Markup Language,超文本标记语言);
  • 作为文档传递协议的 HTTP ;
  • 指定文档所在地址的 URL(Uniform Resource Locator,统一资源定位符)。

WWW 这一名称, 是 Web 浏览器当年用来浏览超文本的客户端应用程序时的名称。现在则用来表示这一系列的集合,也可简称为 Web。


⛪2. HTTP知识预备


2.1 TCP/IP协议

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

上篇文章我们曾经讲过,TCP/IP模型将网络分为了四层,将不同的任务划分,每层只要完成自己的任务即可,完成了每层间的解耦,同时上层依赖下层的服务以实现自己的功能。HTTP是一个建立在TCP/IP协议族上的应用层协议,所以,要利用HTTP发送数据,就要通过上图过程。

我们用 HTTP 举例来说明,

  • 首先作为发送端的客户端在应用层(HTTP 协议)发出一个想看某个 Web 页面的 HTTP 请求。
  • 接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
  • 在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了。
  • 接收端的服务器在链路层接收到数据, 按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP。

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

2.2 URI 和 URL

URL (Uniform Resource Locator) ,我们称为统一资源定位符。它是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。也就是我们经常说的网址。

  • 具体格式为:

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

URI (Uniform Resource Identifier) ,我们称为统一资源标识符 。URI 就是由某个协议方案表示的资源的定位标识符。

  • URI 与 URL 的联系:

URI 用字符串标识某一互联网资源, 而 URL 表示资源的地点(互联网上所处的位置),可见 URL 是 URI 的子集URI 可以分为 URL + URN (统一资源名称) ,打个比方,URI 相当于一个人,URL 就是这个人的住址,URN 就是这个人的名字。

所以,URL 必定也是 URI

  • URI 与 URL 的区别:

URI 不一定是 URL,根据上文,URI 中还有一个 URN ,它只是命名资源,而不定位资源。

2.3 DNS服务

DNS( Domain Name System)**DNS 协议提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务 **,和 HTTP 协议一样位于应用层的协议。

相比IP地址这种纯数字,域名这种字母+数字的组合让人更加容易记忆,比如:百度的IP地址为110.242.68.3 ,域名为www.baicdu.com。可见,大多数用户在访问网站时,都习惯使用域名。

但我们知道在网络上,IP地址+端口号才能定位一个唯一的服务,所以就需要 DNS服务 将域名解析为 IP地址。

具体工作场景如下图:

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++


🕋3. HTTP协议格式


请求报文

POST /data/index HTTP/1.1
Host: baichen.com
Connection: keep-alive
Content-Type: text/html; charset=utf8
Content-Length: 16

name=chen&age=37

请求报文的构成为:

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

由此,我们可以得到请求报文的格式为:

  • 请求行: 方法 + URL + 协议版本

  • 请求头部: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔。

  • 空行:空行用于标识请求头部结束,请求正文开始。

  • 请求正文: 空行后面的内容都是请求正文,内容为应发送的数据。请求正文允许为空字符串。如果请求正文存在, 则在请求头部中会有一个Content-Length属性来标识请求正文的长度。

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

这里要解释一个问题,为什么前文讲解URL的结构这么复杂,但是在上面的请求报文中却好像只有目录结构,而没有协议、域名等部分?

当客户端请求访问资源而发送请求时, URL 需要将作为请求报文中的请求 URL 包含在内。指定请求 URI 的方式有很多。

  • 指定完整的URL
GET http://www.baichen.com/index.html HTTP/1.1
  • 在首部字段Host中写明网络域名或IP地址
GET / HTTP/1.1
Host: www.baichen.com

HTTP请求的'/'并不是根目录,而是web根目录,意味着我们要请求该网站的首页
  • 对于针对服务器本身的访问,可以用* 来代替请求 URL
OPTIONS * HTTP/1.1 -- 查询服务器支持的方法

响应报文

HTTP/1.1 200 OK
Date: Tue, 10 Jul 2012 06:50:15 GMT
Content-Length: 362
Content-Type: text/html

<html>
…

响应报文的构成为:

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

由此,我们可以得到响应报文的格式为:

  • 相应行: 协议版本 + 状态码 + 状态码描述
  • 响应头部: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔。
  • 空行:空行用于标识响应头部结束,响应正文开始。
  • 响应正文: 空行后面的内容都是响应正文,内容为应发送的数据。响应正文允许为空字符串。如果响应正文存在,则在响应头部中会有一个Content-Length属性来标识响应正文的长度;如果服务器返回了一个html页面,那么html页面内容就是在响应正文中。

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++


🕌4. HTTP的方法


向请求 URL 指定的资源发送请求报文时,采用称为方法的命令。方法的作用在于, 可以指定请求的资源按期望产生某种行为。方法中有 GETPOSTHEAD 等。

eg.

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • HTTP支持的方法详见下表:
方法 说明 支持的HTTP协议版本
GET 获取资源 1.0、1.1
POST 传输实体主体 1.0、1.1
PUT 传输文件 1.0、1.1
HEAD 获得报文首部 1.0、1.1
DELETE 删除文件 1.0、1.1
OPTIONS 询问支持方法 1.1
TRACE 追踪路径 1.1
CONNECT 要求用隧道协议连接代理 1.1
LINK 建立和资源之间的联系 1.0
UNLINE 断开连接关系 1.0

LINK 和 UNLINK 方法已经被 HTTP/1.1 弃用,这两个方法只需了解即可。

GET:获取资源

GET 方法用来请求访问已被 URL 识别的资源。指定的资源经服务器端解析后返回响应内容。

请求报文:
GET / HTTP/1.1
Host: www.baichen.com
Connection: keep-alive
User-Agent: XXXXX

响应报文:
HTTP/1.1 200 OK
Content-Type: text/plain

hello, i'm from the futurn

上面就是一个经典的使用GET方法的例子,GET方法是一个使用非常频繁的方法,用于获取指定 URL 的资源,当我们访问一个网站的时候,第一次使用的方法基本都是GET,以获取网页信息。

POST:传输实体主体

POST 方法用来传输实体的主体。虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行传输,而是用 POST 方法。虽说 POST 的功能与 GET 很相似,但POST 的主要目的并不是获取响应的主体内容。

:使用GET方法传输的内容直接会在URL上显示,而用POST方法传输的内容会在报文正文传输,而不会在URL上直接显示。

POST / HTTP/1.1
Host: www.baichen.com
Content-Length: 1560(1560字节的数据)

PUT:传输文件

PUT 方法用来传输文件。就像 FTP 协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存到请求 URL 指定的位置。 这个方法由于安全性较低,所以大部分主流网站不会支持这个方法或者配合验证机制使用此方法。

PUT / HTTP/1.1
Host: www.baichen.com
Content-Type: text/html
Content-Length: 1560(1560字节的数据)

HEAD:获得报文首部

HEAD 方法和 GET 方法一样,只是不返回报文主体部分,用于确认 URL 的有效性及资源更新的日期时间等。

HEAD /index.html HTTP/1.1
Host: www.baichen.com

DELETE:删除文件

DELETE 方法按请求 URL 删除指定的资源。DELETE 方法和 PUT 效果正好相反,所以 DELETE 也具有安全性问题,一般不会单独使用。

DELETE /index.html HTTP/1.1
Host: www.baichen.com

OPTIONS:询问支持的方法

OPTIONS 方法用来查询针对请求 URL 指定的资源支持的方法。

请求:
OPTIONS * HTTP/1.1
Host: www.baichen.com

返回:
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
(返回服务器支持的方法)

TRACE:追踪路径

TRACE 方法是让 Web 服务器端将之前的请求通信环回给客户端的方法 .客户端通过 TRACE 方法可以查询发送出去的请求是怎样被加工修改 / 篡改的。这是因为,请求想要连接到源目标服务器可能会通过代理中转, TRACE 方法就是用来确认连接过程中发生的一系列操作。

发送请求时, 在 Max-Forwards 首部字段中填入数值,每经过一个服务器端就将该数字减 1, 当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK 的响应

请求:
TRACE / HTTP/1.1
Host: WWW.baichen.com
Max-Forwards: 2

返回:
HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 1024

TRACE / HTTP/1.1
Host: www.baichen.com
Max-Forwards: 2(返回响应包含请求内容)

CONNECT:要求用隧道协议连接代理

CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。

使用隧道通信相当于是在客户端和服务器之间建立了一个隧道,两者的报文从隧道走,可以保证通信的连续和安全。

CONNECT方法使用格式:
CONNECT 代理服务器名:端口号 HTTP版本

eg.
CONNECT 101.58.2.1:8080 HTTP/1.1
Host: www.baichen.com

🛕5. HTTP的状态码


状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。 借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。

eg.

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

5.1 状态码分类


状态码 类别 原因短语
1XX Informational(信息性状态码) 接收的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错

RFC2016上规定的状态码有40余种,再加上WebDAV等的状态码,一共有60余种。但是,常用的状态码大概就14种,下面由我向大家介绍这14种状态码。


5.2 2XX 成功


2XX 的响应结果表明请求被正常处理了。

200 OK

表示从客户端发来的请求在服务器端被正常处理了。

204 No Content

该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。 另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后, 返回 204 响应,那么浏览器显示的页面不发生更新 。

206 Partial Content

该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由 Content-Range 首部字段指定范围的实体内容。


5.3 3XX 重定向


3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。

301 Moved Permanently

永久性重定向。该状态码表示请求的资源已被分配了新的 URL,以后应使用资源现在所指的 URL。也就是说,如果已经把资源对应的 URL 保存为书签了,这时应该按 Location 首部字段提示的 URL 重新保存。

永久性重定向一般用于网址搬迁、网站升级等服务,需要用 Location: 新的地址 指明跳转的地址,301状态码会建议浏览器更新书签,将其指向新网址,但是浏览器的实现各不相同,可能需要你手动修改,也可能帮你修改。

302 Found

临时性重定向。该状态码表示请求的资源已被分配了新的 URL,希望用户(本次)能使用新的 URL 访问。

一般用于网站抢修,或者跳转至登录页面等,这个状态码也需要配合 Location: 新的地址 一起使用,这个状态码不会建议浏览器更新书签。

303 See Other

该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别。

:当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做。

304 Not Modified

该状态码表示客户端发送附带条件的请求 A 时,服务器端允许请求访问资源,但未满足条件的情况。 304 状态码返回时,不包含任何响应的主体部分。

307 Temporary Redirect

临时重定向。该状态码与 302 Found 有着相同的含义。尽管 302 标准禁止 POST 变换成 GET,但实际使用时大家并不遵守。

307 会遵照浏览器标准, 不会从 POST 变成 GET。但是,对于处理响应时的行为,每种浏览器有可能出现不同的情况。


5.4 4XX 客户端错误


4XX 的响应结果表明客户端是发生错误的原因所在。

400 Bad Request

该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。

401 Unauthorized

该状态码表示发送的请求需要有通过 HTTP 认证( BASIC 认证、DIGEST 认证)的认证信息。 另外若之前已进行过 1 次请求,则表示用户认证失败。

返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询( challenge)用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。

403 Forbidden

该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由, 但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。

未获得文件系统的访问授权, 访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能是发生 403 的原因。

404 Not Found

该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。


5.5 5XX服务器错误


5XX 的响应结果表明服务器本身发生错误。

500 Internal Server Error

该状态码表明服务器端在执行请求时发生了错误。

503 Service Unavailable

该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。 如果事先得知解除以上状况需要的时间,最好写入 Retry After 首部字段再返回给客户端。


状态码的本意是用来快速获取请求状态,但是在很多场景下,我们会发现状态码和出错的地方根本就对不上。归根到底,状态码并不是一种强制性的命令,而是一种建议式的反馈,很多浏览器对于同一状态码的处理可能都千差万别,比如,404 状态码在谷歌浏览器上,如果返回有实体主体,那么谷歌浏览器并不会理会 404 状态码,而是显示返回的实体主体的内容,但是404 状态码在Edge浏览器上就会强制执行 404 Not Fount。

虽然网络上的状态码鱼龙混杂,但是我们自己写的状态码一定要符合标准,这样有利于养成良好的代码习惯和排查错误。


🕍6. HTTP的首部


  • HTTP 协议的请求和响应报文中必定包含 HTTP 首部。首部内容为客户端和服务器分别处理请求和响应提供所需要的信息。

  • HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间以 HTTP 协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到传递额外重要信息的作用。使用首部字段是为了给浏览器和服务器提供报文主体大小、 所使用的语言、认证信息等内容。

eg.

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

HTTP 首部字段分类

  • 请求报文

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • 响应报文

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

HTTP 首部字段结构

首部字段名: 字段值
eg.
Content-Type: text/plain, charset=utf-8  -- 报文主体的对象类型,字体协议为utf-8协议

HTTP 首部字段类型

  • 请求首部字段
  • 响应首部字段
  • 通用首部字段
  • 实体首部字段

HTTP 首部字段概览

  • 通用首部字段

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • 请求首部字段

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • 响应首部字段

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • 实体首部字段

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

Connection

HTTP/1.1 之前的 HTTP 版本的默认连接都是非持久连接,也叫短连接。HTTP 协议是基于 TCP 协议的,所以要进行一次会话必须要经过建立连接、请求、响应、断开连接的过程,这样每进行一次请求和响应都要建立连接和断开连接,非常耗费时间,这是由于以前传输的都是体积不太大文本等文件,不需要持久连接。但是,现在由于网络传输需求的迅速发展,持久连接已经成为了 HTTP 连接的必然。

为此,如果想在旧版本的 HTTP 协议上维持持续连接,则需要指定 Connection 首部字段的值为 Keep-Alive

Connection: Keep-Alive

HTTP/1.1 版本的默认连接都是持久连接,也叫长连接。为此,客户端会在持久连接上连续发送请求。 当服务器端想明确断开连接时, 则指定
Connection 首部字段的值为 Close。

Connection: Close

Connection 字段还有控制不再转发给代理的首部字段的功能,但是这里主要是讲解长短连接的概念

Cookie

Cookie 的工作机制是用户识别及状态管理。 Web 网站为了管理用户的状态会通过 Web 浏览器,把一些数据临时写入用户的计算机内。接着当用户访问该Web网站时,可通过通信方式取回之前发放的Cookie。

Cookie其实是一种特别我们经常使用的字段,因为HTTP协议是一种无状态的协议,也就意味着:本次会话和上一次会话之间没有任何关系,互不影响。但是,我们日常使用B站等视频网站时,却能够保持登录状态,这是因为HTTP协议不是无状态的吗?

当然不是,HTTP协议引入了 Cookie 值作为“会话保持”的媒介,那么 cookie 到底是什么呢?

【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

简单来说,Cookie 是一种保存在内存或者本地磁盘上的数据文件,其中保存着客户端的各种信息。

  • Set-Cookie

服务器准备开始管理客户端的状态时,会使用 Set-Cookie 字段事先设置客户端Cookie

Set-Cookie 字段的属性:

属性 说明
NAME=VALUE 赋予Cookie的名称和其值(必需项)
expires=DATE Cookie的有效期(若不明确指定则默认为浏览器关闭前为止)
path=PATH 将服务器上的文件目录作为Cookie的适用对象(若不指定则 默认为文档所在的文件目录)
domain=域名 作为Cookie适用对象的域名 (若不指定则默认为创建 Cookie 的服务器的域名)
Secure 仅在HTTPS安全通信时才会发送Cookie
HttpOnly 加以限制,使Cookie不能被JavaScript脚本访问

eg.

Set-Cookie: id=1; password=123456; expires=Tue, 05 Jul 2023 18:43:32 GMT; path=/; domain=baichen.com;
  • Cookie

当被服务器用 Set-Cookie 设置了 Cookie 以后,客户端发送请求报文时,会在头部字段添加一个 Cookie 字段,用来保存服务器设置的 Cookie 。接收到多个 Cookie 时,同样可以以多个 Cookie 形式发送。

一般来说,每个Cookie 的大小不能超过 4KB

eg.

Cookie: id=1; password=123456;
  • Set-Cookie 和 Cookie 实例

本会话的源代码见简易HTTP服务器,以下报文都是基于下文代码获得,大家可以自行验证。

请求:
GET / HTTP/1.1
Host: baichen.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: xxx
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

响应:
HTTP/1.0 200 OK
Set-Cookie: id=1111       -- 设置Cookie
Set-Cookie: password=2222 -- 设置Cookie
Content-Type: text/html, charset=utf-8
Content-Length: XXX

.....

请求:
POST / HTTP/1.1
Host: baichen.com
Connection: keep-alive
Content-Length: 37
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: id=1111; password=2222 --- Cookie值

name=%E7%99%BD%E6%99%A8&passwd=123456
Session

如果有人通过一些手段截取了我们的 Cookie 文件,如果Cookie使用的是明文传递,那么我们的账号、密码等个人信息会被窃取,如果Cookie使用的是加密传递,虽然攻击者不能获得我们的私密信息,但是他可以使用我们的Cookie访问各种私密资源,甚至做违法之事。当然,前文提到了Cookie在配置良好的情况下,安全性还不错,但是总有被劫持的风险。

Session 就是为了解决上述问题而设计的方案,具体做法是:存储于服务器上的 Session 对象存储特定用户会话所需的属性及配置等私密信息,第一次访问该服务器的用户会创建一个唯一的 Session 对象存储私密信息,以后访问该服务器时就根据用户信息读取对应的信息。

由于 Session 对象存储在服务器上,不在客户端本地保存,所以不会被劫持,这样就解决了安全的问题。但是可以只使用 Session 方案吗?是不行的,Session 是需要消耗服务器服务器资源的,会增加运行成本,所以并不能将大规模数据都保存到 Session 对象中。一般的方案是:Cookie 和 Session 配合使用,以达到安全和会话保持的平衡。

  • Cookie 和 Session 对比
    1. Cookie 数据存放在客户端上,Session 数据放在服务器上。
    2. Cookie不是很安全,别人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗。
    3. Session 对比 Cookie 来说更安全,Session 会在一定时间内保存在服务器上,但是当访问增多,会比较占用服务器的性能。
    4. 一般的方案是:CookieSession 配合使用,以达到安全和会话保持的平衡。

⛩️7. 搭建简易HTTP服务器


这次实现的HTTP服务器是一个最简单的HTTP服务器,主要是为了让大家了解HTTP的使用,实现的功能有显示网页,上传数据,设置Cookie等。

  • 效果图如下:
    【网络】HTTP协议详解,网络,网络,http,网络协议,服务器,c++

  • 首先,封装一个套接字库。
#pragma once

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>


class Sock
{
public:
    static int Socket()
    {
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if(sock < 0)
        {
            std::cerr << "socket failed" << std::endl;
            exit(1);
        }
    }

    static void Bind(int sock, uint16_t port)
    {
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;
        
        if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            std::cerr << "bind failed" << std::endl;
            exit(2);
        }
    }

    static void Listen(int sock)
    {
        const int backlog = 5;
        if(listen(sock, backlog) < 0)
        {
            std::cerr << "listen failed" << std::endl;
            exit(3);
        }
    }

    // tcp通信直接在套接字中写就可以,所以可以不用返回客户端的信息
    static int Accept(int sock)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        
        int new_sock = accept(sock, (struct sockaddr*)&peer, &len);
        if(new_sock < 0)
        {
            std::cerr << "accept failed" << std::endl;
            exit(4);
        }

        return new_sock;
    }

    static void Connect(int sock, const std::string& ip, uint16_t port)
    {
        struct sockaddr_in server;
        memset((void*)&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        server.sin_addr.s_addr = inet_addr(ip.c_str());

        if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
        {
            std::cerr << "connect failed" << std::endl;
            exit(5);
        }
        else
        {
            std::cout << "connect succeed" << std::endl;
        }
    }
};
  • HTTP服务:
#include "Sock.hpp"
#include <fstream>
#include <sys/stat.h>

// 设置网页根目录
#define WWWROOT "./wwwroot/"
#define HOME_PAGE "index.html"

void Usage(std::string args)
{
    std::cout << "Usage : " << args << " server_port" << std::endl;
}

void *handler(void *args)
{
    pthread_detach(pthread_self());

    int sock = *(int *)args;
    delete (int *)args;

#define NUM 1024 * 10
    char buf[NUM];
    memset(buf, 0, sizeof(NUM));
    // 接收请求报文
    ssize_t sz = recv(sock, buf, sizeof(buf) - 1, 0);
    if (sz > 0)
    {
        buf[sz] = 0;
        std::cout << buf << std::endl;

        std::string fileloc = WWWROOT;
        fileloc += HOME_PAGE;
        // fileloc += "a/b";
        // 读取网页信息
        std::ifstream ifs(fileloc);

        if (!ifs.is_open())
        {
            std::string http_response = "HTTP/1.0 404 NotFount";
            http_response += "Content-Type: text/html, charset=utf-8";
            http_response += "\n";
            http_response += "<html><p> 你访问的资源不存在 </p></html>";

            send(sock, http_response.c_str(), http_response.size(), 0);
        }
        else
        {
            // 构建响应报文
            std::string line;
            std::string echo;

            while (std::getline(ifs, line))
            {
                echo += line;
            }

            struct stat fst;
            stat(fileloc.c_str(), &fst);

            std::string http_response = "HTTP/1.0 200 OK\n";
            // std::string http_response = "HTTP/1.0 404 NotFount";
            // std::string http_response = "HTTP/1.0 302 Temporarily Move\n";
            // http_response += "Location: http://www.bilibili.com";

            http_response += "Set-Cookie: id=1111\n";
            http_response += "Set-Cookie: password=2222\n";
            http_response += "Content-Type: text/html, charset=utf-8\n";
            http_response += "Content-Length: ";
            http_response += std::to_string(fst.st_size);
            http_response += "\n\n";
            http_response += echo;
            // http_response += "\n";
            http_response += "\n";

            // std::string http_response = "HTTP/1.0 200 OK\n";
            // http_response += "Content-Type: text/plain\n";
            // http_response += "\n";
            // http_response += "hello, i'm from the futurn\n";
            
            // 发送响应报文
            send(sock, http_response.c_str(), http_response.size(), 0);
        }
    }
    close(sock);
    return nullptr;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(-1);
    }
    int sock = Sock::Socket();

    Sock::Bind(sock, atoi(argv[1]));
    Sock::Listen(sock);

    while (true)
    {
        pthread_t tid;
        int new_sock = Sock::Accept(sock);
        // int *psock = new int(new_sock);

        // pthread_create(&tid, nullptr, handler, psock);
    }

    return 0;
}
  • index网页构建:
<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h5>hello, i'm baichen!</h5>
        <h5>hello, 我是表单!</h5>
        <!-- action是数据提交到哪 method是提交数据时使用什么方法,可自行测试GET、POST方法传递信息的不同 -->
        <form action="/a/handler_form" method="POST">
            姓名:<input type="text" name="name"><br/>
            密码:<input type="password" name="passwd"><br/>
            <input type="submit" value="登录">
        </form>
    </body>
</html>


📕后记


参考书籍:《图解HTTP》

本篇文章白晨讲解了HTTP的背景知识、协议结构、状态码、相关技术知识以及服务器的编写,也算是讲解的非常全面了。其中也有一些知识由于篇幅问题,白晨并没有展开说明,比如HTTP的首部字段等,需要大家在这篇文章的基础上自行进行相关学习。下一篇文章,白晨准备讲解HTTP协议的升级版——HTTPS协议,通过学习HTTPS的学习,相信你会对HTTP协议有更深的理解。

如果大家有什么想和白晨交流的,欢迎私信白晨🎊。


如果讲解有不对之处还请指正,我会尽快修改,多谢大家的包容。

如果大家喜欢这个系列,还请大家多多支持啦😋!

如果这篇文章有帮到你,还请给我一个大拇指 👍和小星星 ⭐️支持一下白晨吧!喜欢白晨【网络】系列的话,不如关注👀白晨,以便看到最新更新哟!!!

我是不太能熬夜的白晨,我们下篇文章见。文章来源地址https://www.toymoban.com/news/detail-784227.html

到了这里,关于【网络】HTTP协议详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBootWeb入门、HTTP协议、Web服务器-Tomcat

    目录 一、SpringBootWeb入门 二、HTTP协议 HTTP-请求协议 HTTP-响应协议 HTTP-协议解析 三、Web服务器-Tomcat 服务器概述 Tomcat 直接基于SpringFramework进行开发,存在两个问题:配置繁琐、入门难度大 通过springboot就可以快速的帮我们构建应用程序,所以springboot呢,最大的特点有两个 :

    2024年01月15日
    浏览(42)
  • 初识http协议,简单实现浏览器和服务器通信

    平时俗称的 “网址” 其实就是说的 URL,例如在百度上搜索一个C++ 可以看到这段网址前面有个 https 那么这个就代表着使用的是https协议,现在都是使用https协议,不过还是需要认识以下http协议 像 / ? : 等这样的字符, 已经被url当做特殊意义理解了. 因此这些字符不能随意出现。

    2024年02月14日
    浏览(45)
  • 〖Web全栈开发③〗—HTTP协议和静态web服务器

    🏘️🏘️个人简介:以山河作礼。 🎖️🎖️: Python领域新星创作者,CSDN实力新星认证,阿里云社区专家博主 🎁🎁:Web全栈开发专栏:《Web全栈开发》免费专栏,欢迎阅读! TCP (Transmission Control Protocol) 是在互联网协议(IP)上的一种基于连接(面向连接)的传输层协议 。数据

    2024年02月05日
    浏览(42)
  • 【网络进阶】HTTP服务器(一)

    HTTP(超文本传输协议,Hypertext Transfer Protocol)是一种用于传输超文本数据(如HTML、图片、视频等)的应用层协议。它允许互联网上的客户端和服务器之间通过请求和响应进行双向通信。HTTP 是互联网的基石,为 Web 浏览器和 Web 服务器之间的数据交换提供了标准规范。 HTTP 基

    2024年02月02日
    浏览(44)
  • Java服务器调用Python服务器进行交互:基于Http协议的Restful风格调用(Springboot/FastApi)

    实现Java服务器调用Python服务器进行交互以及数据传输,可采用以下方法,亲测有效: 基于Restful风格进行请求调用: 框架 : Java服务器采用Springboot框架进行搭建服务 python服务器采用FastApi框架进行搭建服务 思路 :前端–Java–python–Java–前端 代码设计 :Axios-@PostMapping-请求

    2024年04月26日
    浏览(42)
  • 个人网站搭建 服务器http切换到https 网站协议切换到https

    博主自行搭建一个个人网站,国内的服务器和域名都要实名或者备案,觉得太麻烦了;于是用的是国外的,用的是知速云+cf。写这篇文章主要是想记录一下几天踩过的坑,帮助大家更快搭建好自己的网站。(同时也方便自己日后回顾) 推荐通过docker进行安装,方便管理。 1)

    2024年01月17日
    浏览(50)
  • Java 网络编程 —— 创建非阻塞的 HTTP 服务器

    HTTP 客户程序必须先发出一个 HTTP 请求,然后才能接收到来自 HTTP 服器的响应,浏览器就是最常见的 HTTP 客户程序。HTTP 客户程序和 HTTP 服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写。HTTP 严格规定了 HTTP 请求和 HTTP 响应的数据格式,只要 HTTP 服务器

    2024年02月06日
    浏览(45)
  • WebDav协议相关软件@简单配置局域网内的http和WebDav服务器和传输系统

    windows自带 IIS webdav windows自带的服务,启用相关功能后还要进行一系列的配置 而且在WebDav客户端上传到站点的文件大小存在限制问题 总体体验并不好,因此推荐第三方专业软件,灵活而且易于配置 第三方软件 CuteHttpFileServer | iscute.cn👺 提供了windos端的命令行程序和图形界面程序

    2024年01月21日
    浏览(52)
  • SpringBoot + Vue2项目打包部署到服务器后,使用Nginx配置SSL证书,配置访问HTTP协议转HTTPS协议

    配置nginx.conf文件,这个文件一般在/etc/nginx/...中,由于每个人的体质不一样,也有可能在别的路径里,自己找找... 证书存放位置,可自定义存放位置 两个文件 后端配置 把.pfx拷贝到resource下,然后配置一下yml

    2024年02月02日
    浏览(70)
  • libevent高并发网络编程 - 04_libevent实现http服务器

    链接: C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 在libevent中,HTTP的实现主要是通过 evhttp 模块来完成的。 evhttp 提供了一个高层次的HTTP服务器接口,可以处理HTTP请求并发送HTTP响应。 在源码中,libevent的HTTP协议处理主要是通过 evhttp 模块来完成的。

    2024年02月15日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包