HTTP 协议
是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网( WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP 是一个基于 TCP/IP 通信协议来传递数据(HTML 文件、图片文件、查询结果等)。
HTTP协议用于在客户端和服务器之间传输超文本。它是 Web 的基础,可用于检索和提交信息,例如 HTML 文件、图像、样式表等。HTTP 是无状态的,也就是说每个请求都是独立的,服务器不会存储任何有关先前请求的信息。HTTP 协议常用于浏览器与 Web 服务器之间的通信。
在WWW上,每一信息资源都有统一的且在网上的地址,该地址就叫URL(Uniform Resource Locator,
统一资源定位器
),它是WWW的统一资源定位标志,就是指网络地址。平时我们俗称的"网址"
其实就是说的URL
,URL标识了Internet上的每一个唯一的网页。
协议方案名:
http://
表示的是协议名称,表示请求时需要使用的协议,通常使用的是HTTP协议或者是安全协议HTTPS。
常见的应用层协议:
DNS
(Domain Name System)协议:域名系统。FTP
(File Transfer Protocol)协议:文件传输协议。TELNET
(Telnet)协议:远程终端协议。HTTP
(Hyper Text Transfer Protocol)协议:超文本传输协议。HTTPS
(Hyper Text Transfer Protocol over SecureSocket Layer)协议:安全数据传输协议。SMTP
(Simple Mail Transfer Protocol)协议:电子邮件传输协议。POP3
(Post Office Protocol - Version 3)协议:邮件读取协议。SNMP
(Simple Network Management Protocol)协议:简单网络管理协议。TFTP
(Trivial File Transfer Protocol)协议:简单文件传输协议。
登录信息:
usr:pass
表示的是登录认证信息,包括登录用户的用户名和密码,不过登录信息一般不显示在URL中,绝大部分URL中的这个字段是被省略的,因为登录信息可以通过其他方案交给服务器。
服务器地址:
www.example.jp
表示的是服务器地址,也叫做域名,比如:www.baidu.com,www.jd.com等。
域名可以被解析成IP地址:
在这里我们需要知道的是:虽然IP地址可以标识公网内的一台主机,但是IP地址一般不会直接给用户看到,因为用户看到IP地址后并不知道该IP地址的网站是干什么的,但是如果使用www.baidu.com或者www.qq.com这种网址的方式访问网站,那么用户至少可以知道这两个域名对应的是哪两家公司。
域名和IP地址是等价的,我们同样可以使用IP地址来访问网址,但是URL呈现出来是给用户看的,所以URL中以域名的方式表示服务器的地址。
服务器端口号:
80表示的是服务器的端口号,HTTP协议和套接字编程都是位于应用层的,因此应用层协议同样也需要有明确的端口号。
当然,当我们在使用某种协议时,该协议就是在为我们提供服务,因此一般常用的服务和端口号之间的关系都是一一对应的,所以我们在使用某种协议时并不需要明确指定端口号。因此在URL中服务器的端口号一般都是被省略的。
常见协议对应的端口号:
- HTTP (Hyper Text Transfer Protocol) 端口号:80
- HTTPS (Secure Hyper Text Transfer Protocol) 端口号:443
- FTP (File Transfer Protocol) 端口号:21
- SMTP (Simple Mail Transfer Protocol) 端口号:25
- POP3 (Post Office Protocol version 3) 端口号:110
- IMAP (Internet Message Access Protocol) 端口号:143
- DNS (Domain Name System) 端口号:53
- DHCP (Dynamic Host Configuration Protocol) 端口号:67/68
- Telnet (Terminal Emulation) 端口号:23
- SSH (Secure Shell) 端口号:22
- NTP (Network Time Protocol) 端口号:123
- SNMP (Simple Network Management Protocol) 端口号:161/162
- RDP (Remote Desktop Protocol) 端口号:3389
- SIP (Session Initiation Protocol) 端口号:5060/5061
- ICQ (Internet Control Message Protocol) 端口号:7
- IRC (Internet Relay Chat) 端口号:194
- BitTorrent 端口号:6881-6889
带层次的文件路径:
/dir/index.htm
表示的是要访问的资源所在的路径,访问服务器的目的是获取服务器上的某种资源,通过前面的域名和端口号已经能够找到对应的服务器进程了,接下来我们需要指明该资源所在的路径。
除了请求网页资源外,我们还有可能向服务器请求视频、音频、图片等资源。所以HTTP叫做超文本传输协议。
在URL当中的路径分隔符用 /
表示而不是 \
证明了大多数的服务器都是部署在Linux下的。
查询字符串:
uid=1
表示的是请求时提供的额外参数,这些参数一般都是以键值对的形式,通过&服务分隔。当然我们使用百度搜索时提供的搜索关键字也在其中。
片段标识符:
ch1表示的是片段标识符,是对资源的部分补充,当我们在看图片的时候,URL当中就会出现片段标识符,当我们切换到其他图片时这个符号也会发生变化。
HTTP是基于请求和响应的应用层服务器,作为客户端,我们可以向服务器发起请求,服务器收到这个请求后,会对这个请求做数据分析,然后构建response,完成一次HTTP请求,这种基于request和response的工作方式,一般被称为cs或者bs模式,c表示client,s表示server,b表示browser。
HTTP请求协议的格式:
- 请求行:请求方法 + url + http版本
- 请求报头:请求的属性,这些属性都是以key: value的形式按行陈列的。
- 空行:遇到空行表示请求报头结束。
- 请求正文:请求正文允许为空字符串,如果请求正文存在,则在请求报头中会有一个Content-Length属性来标识请求正文的长度。
其中,前面三部分是一般是HTTP协议自带的,是由HTTP协议自行设置的,而请求正文一般是用户的相关信息或数据,如果用户在请求时没有信息要上传给服务器,此时请求正文就为空字符串
这里的空行
可以将可以将HTTP的报头和有效载荷进行分离。当服务器收到一个HTTP请求时,就可以按行进行读取,如果读取到空行则说明已经将报头读取完毕了。
HTTP响应协议格式如下:
- 状态行:http版本 + 状态码 + 状态码描述
- 响应报头:响应的属性,这些属性都是以key: value的形式按行陈列的。
- 空行:遇到空行表示响应报头结束。
- 响应正文:响应正文允许为空字符串,如果响应正文存在,则响应报头中会有一个Content-Length属性来标识响应正文的长度。比如服务器返回了一个html页面,那么这个html页面的内容就是在响应正文当中的。
HTTP响应和HTTP请求一样,都是通过读取空行来分离报头和有效载荷的。
构建HTTP请求
因为HTTP协议的底层使用的是传输层的TCP协议,因此我们可以通过编写一个TCP套接字服务器。再使用浏览器作为客户端来访问该服务器,此时服务器是直接使用TCP套接字来读取浏览器发来的HTTP请求的,此时服务器这端没有应用层对这个HTTP协议进行任何解析,因此我们可以直接将浏览器发来的HTTP请求进行打印输出,此时就可以直接看到HTTP请求的基本构成。
因为浏览器发起请求时默认使用的就是HTTP协议,因此我们直接输入网址时就默认以HTTP协议来向服务器发起请求。同时url当中的 /
表示的是web根目录,它可以是我们服务器上的任何一个目录,由我们自己指定,不一定是Linux的根目录。
请求行当中的url表示我们要访问该服务器上的哪一路径下的资源。请求报头中全部都是以 key:value
形式按行列出的各种请求属性,请求属性之后有一个空行,空行之后的就是本次HTTP请求的正文,因为此时的请求正文为空字符串,所以这里有两个空行。
httpServer.hpp
Main.cc
构建HTTP响应
当服务端读取到客户端发来的HTTP请求后,需要对这个HTTP请求进行各种数据分析,然后构建成对应的HTTP响应发给客户端。这里我们可以给浏览器返回一个固定的HTTP响应。我们可以将当前服务程序所在的路径作为web根目录。然后再该更目录下创建一个文件夹,然后里面写一些简单的html作为当前服务器的首页。
当浏览器向服务器发起HTTP请求时,当向 /
发起默认请求时我们将这个网页响应给浏览器,此时这个html文件的内容就应该放在响应正文中,我们只需要读取该文件当中的内容,然后将其作为响应正文即可。
index.html:
Main.cc
Util.hpp
使用telnet
工具也可以访问服务器:
HTTP请求和HTTP响应当中的请求行中都包含了http的版本信息,分别表示了客户端的HTTP版本和服务器的HTTP版本。客户端在发起HTTP请求时,会告诉服务器自己所使用的HTTP版本,此时服务器就可以根据客户端使用的HTTP版本,为客户端提供对应的服务,而不至于因为双方使用的HTTP版本不同而导致无法正常通信。因此为了保证良好的兼容性,通信双方需要交互一下各自的版本信息。
HTTP常见的方法如下:
GET
方法和POST
方法:
GET
方法用于获取某种资源信息,POST
方法用于将数据上传给服务器,但实际生活中上传数据时也有可能使用GET方法,比如百度官网提交数据时实际使用的就是GET方法。
- GET方法通过url传参
- POST方法通过正文传参
因为url的长度是有限的,而正文则可以很长,所以使用POST方法通过正文传参可以携带更多的数据,同时,使用POST方法传参更加私密,因为POST方法不会将我们所提交的参数回响到url当中。但是两者都不安全,想要更加安全只能通过加密来实现。
GET和POST的区别:
表单(Form) 是 HTML 中一种常用的元素,它是用来接受用户输入的一种方式。表单包含了各种表单元素,如文本框、单选框、复选框、下拉框等,用户可以通过这些元素输入信息,然后通过表单提交(Submit)按钮将这些信息发送到后端服务器。
index.html
当前我们使用的是 GET
方法提交参数,当我们提交完成用户名和密码后我们的用户名和密码就会被自动同步到 url
当中。
当我们将提交表单的方法修改为 POST
方法时,再提交一下看看效果:
最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)
。
Redirect
重定向状态码:
重定向是通过各种方法将各种网络请求重新定了个方向转到其他位置。重定向又分为临时重定向和永久重定向,状态码301
表示的是永久重定向,状态码302
和307
表示的是临时重定向。
永久重定向指的是第一次访问该网址时浏览器会帮我们进行重定向,但后续在访问该网址时就不需要浏览器再次进行重定向了,此时我们访问该网址直接就是重定向后的网址,如果是临时重定向,则每次访问该网址时如果需要进行重定向,那么都需要浏览器来帮我们进行重定向跳转到目标网站。
临时重定向演示:
当然,我们也可以在使用浏览器访问我们的服务时,自动跳转到百度的首页。
Content-Type
:数据类型(text / html 等)Content-Length
:Body 的长度,用于指示客户端应该接收多少字节的响应Host
:客户端告知服务器,所请求的资源是在哪个主机的哪个端口上User-Agent
:声明用户的操作系统和浏览器版本信息referer
:当前页面是从哪个页面跳转过来的location
:搭配 3xx 状态码使用,告诉客户端接下来要去哪里访问Cookie
:用于在客户端存储少量信息,通常用于实现会话(session)的功能
下面我们重点来说一下 Keep-Alive(长连接)
HTTP 的长连接和短连接都是指在 TCP 层面上的连接。HTTP 协议是基于 TCP 协议的,每次 HTTP 请求和响应都需要建立和断开 TCP 连接,因此在高并发场景下会产生大量的 TCP 连接开销,从而影响性能。
短连接指每次HTTP请求和响应都建立一个新的 TCP 连接,并在请求结束后立即关闭连接。这种方式下,每次请求都需要重新建立和断开 TCP 连接,会增加连接管理的负担和开销。在 HTTP/1.0 中,HTTP 默认采用短连接,也就是每次请求和响应都建立和断开一次 TCP 连接。
如今的HTTP/1.1是支持长连接的。所谓的长连接就是建立连接后,客户端可以不断地向服务器一次写入多个HTTP请求,而服务器在上层一次读取这些请求就行了,此时一条连接就可以传送大量的请求和响应。
如果HTTP请求或响应报头当中的Connect字段对应的值是Keep-Alive,就代表支持长连接。
长连接和短连接各有优缺点,长连接可以减少 TCP 连接的建立和断开次数,降低网络开销,但长时间占用连接会增加服务器资源消耗;短连接可以保证每个请求的独立性,减少因单个请求错误导致的影响,但频繁的 TCP 连接建立和断开会影响性能。因此,根据具体的应用场景和需求选择长连接或短连接,或者结合两者的优点,使用 HTTP/2 的多路复用技术。
HTTP的特征:
无状态
:每个 HTTP 请求都是独立的,服务器不会保存任何客户端的请求信息,因此 HTTP 被称为无状态协议。为了维护客户端状态,通常使用 Cookie 和 Session技术。可扩展
:HTTP 报头可以通过添加自定义报头实现扩展功能。灵活
:HTTP 可以传输任何类型的数据,如 HTML、图片、音频、视频等。明文传输
:HTTP 是明文传输的,请求和响应中的所有内容都可以被窃听,因此使用 HTTPS 进行加密。请求 / 响应模型
:HTTP 采用客户端-服务器模型,客户端发送请求,服务器发送响应。无连接
:HTTP 协议不维护连接,连接是 TCP 协议维护的,HTTP直接发起请求和响应即可。缓存
:HTTP 支持缓存,可以通过在响应报头中添加缓存信息控制客户端和服务器的缓存机制。
虽然在HTTP的特征中有 无状态
的特点,但是我们可以发现每次在使用浏览器的时候却不是这样的,当我们在使用账号和密码登陆到一个网站的时候,无论我们将该网站关闭还是将浏览器关闭,当我们再次打开该网站时,我们发现我们的账号还是处于登录状态。
但是在实际应用中,为了实现用户的登录状态等功能,网站会在服务器端保存用户的会话
状态,并分配给用户一个唯一的 会话标识符(Session ID)
,这个会话标识符可以在每次请求时传递给服务器,服务器就可以根据这个标识符识别用户,从而实现用户状态的保持。
Cookie
Cookie
是一种小的文本信息,由服务器发送给客户端的浏览器,然后由浏览器存储在用户的计算机上。它主要用于跟踪和维护Web应用程序的状态,以便在不同的HTTP请求之间保持用户的特定信息。
简单点来说就是,HTTP不支持记录用户状态,我们需要一种技术来帮我们支持,这种技术目前现在已经内置到HTTP协议当中了,他就是Cookie
当我们认证通过后在服务端会进行Set-Cookie
设置,当服务器在对浏览器进行HTTP响应时就会将这个Set-Cookie相应给浏览器,浏览器收到响应后自动提取出Set-Cookie的值,并将其保存在浏览器的Cookie文件中,此时就相当于我们的账号密码等信息保存在了本地浏览器的Cookie文件中。
当我们再次向该网站发起HTTP请求时,该请求当中就会自动包含一个Cookie字段,Cookie字段中携带的就是我们第一次的认证信息。因此之后对端服务器在进行认证时只需要提取出HTTP请求当中的Cookie字段即可。
Cookie的种类:
Cookie本质上就时浏览器当中的一个小文件,文件里记录的是用户的私有信息,Cookie文件可以分为两种:
内存级别
和文件级别
。
文件级的 Cookie 文件是存储在用户计算机上的硬盘上,是一种持久性的 Cookie。它们的过期时间可以设置为一段时间,也可以永不过期。在访问同一个网站时,浏览器会自动发送该网站存储在本地计算机上的 Cookie文件,以便在服务器端进行身份验证和授权操作。
内存级的 Cookie 文件是存储在内存中的临时 Cookie。当浏览器关闭时,它们会自动删除。内存级的 Cookie 可以用于存储一些敏感信息,如密码和银行账户信息等,以提高安全性。
SessionID:
如果我们仅仅使用Cookie是不安全的,因为此时Cookie文件当中是我们的私密信息,一旦Cookie文件泄露我们的隐私信息也会泄露。所以就引入了SessionID这样的概念。
当我们第一次输入账号密码验证成功后,服务端就会生成一个对应的Session ID,并将其发送给客户端。之后,客户端每次请求都会携带这个 Session ID,服务器就可以根据 Session ID 查找对应的会话对象,获取用户的相关信息,从而实现用户状态的保持。这个Session ID与用户信息是不相关的。同时系统会将所有登录用户的Session ID统一维护起来。
本篇博客完整代码