此文已读,从此对HTTP的认识不再一脸茫然,建议收藏

目录

HTTP历史发展

HTTP理解

HTTP相关概念

HTTP相关协议

网络分层模型

域名

HTTP流程

HTTP请求方法

HTTP实体数据

HTTP传输大文件

HTTP的连接管理

HTTP的重定向和跳转

HTTP的Cookie机制

HTTPS

对称加密和非对称加密

数字签名和证书

TLS1.2连接过程

补充

HTTP/1.0和HTTP/1.1区别

HTTP/1.1和HTTP/2区别

CGI与环境变量


HTTP历史发展

  • HTTP/0.9是个简单的文本协议,只能获取文本资源

  • HTTP/1.0确立了大部分现在使用的技术,但它不是正式标准

  • HTTP/1.1是目前互联网上使用最广泛的协议,功能也非常完善

  • HTTP/2基于Google的SPDY协议,注重性能改善,但还未普及

  • HTTP/3基于Google的QUIC协议,是将来的发展方向

文章相关视频讲解:

c/c++Linux后台服务器开发高级架构师学习视频

Linux内核内存管理专题训练营

PS:视频相关学习文档,点击获取

HTTP理解

  • HTTP是一个协议,它确立了计算机之间交流通信的规范,以及相关的各种控制和错误处理方式(协议)

  • HTTP专门用来在两点之间传输数据,不能用于广播、寻址或路由(传输)

  • HTTP传输的是文字、图片、音频、视频等超文本数据(超文本)

HTTP相关概念

  • 万维网(WWW)是互联网(Internet)的一个子集,基于HTTP协议

  • 浏览器是HTTP协议里的请求方,即User Agent

  • 服务器是HTTP协议里的应答方,常用的有Apache和Nginx

  • 内容分发网络(CDN)位于浏览器和服务器之间,主要起到缓存加速的作用

  • 爬虫是另一类User Agent,是自动访问网络资源的程序

  • HTML(超文本标记语言)是HTTP协议传输的主要内容之一

HTTP相关协议

  • TCP/IP

  • DNS(域名系统):域名解析

  • URI/URL/URN URI(统一资源标志符):用来唯一标识互联网上的信息资源,包括URL和URN URL(统一资源定位符) URN(永久统一资源定位符):在资源移动后还能被找到

  • HTTPS(HTTP over SSL/TLS)

  • 代理 正向代理:靠近客户端,代表客户端向服务器发送请求 反向代理:靠近服务器端,代表服务器响应客户端的请求

网络分层模型

  • TCP/IP分为四层,核心是二层的IP和三层的TCP,HTTP在第四层

  • OSI分为七层,基本对应TCP/IP,TCP在第四层,HTTP在第七层

域名

域名使用字符串来代替IP地址,方便记忆

最右边的是顶级域名,然后是二级域名,层级关系向左依次降低

DNS(Domain Name System,域名系统)是一个树状的分布式查询系统。通过主机名,最终得到该主机名对应IP地址的过程叫做域名解析。DNS协议运行在UDP协议之上,使用端口号53

  • 根域名服务器:管理顶级域名服务器,返回com、net、cn等顶级域名服务器的IP地址

  • 顶级域名服务器:管理各自域名下的权威域名服务器,比如com顶级域名服务器可以返回apple.com域名服务器的IP地址

  • 权威域名服务器:管理自己域名下主机的IP地址,比如apple.com权威域名服务器可以返回www.apple.com的IP地址

  • 非权威域名服务器:Google的8.8.8.8,Microsoft的4.2.2.1等

  • 浏览器和操作系统也会对DNS解析结果做缓存

  • 如果操作系统在缓存里找不到DNS记录,就会查找该文件: Linux是/etc/hosts Windows是C:\WINDOWS\system32\drivers\etc\hosts

域名解析分为递归查询和迭代查询两种,实际中是两者结合使用,从终端用户看是递归查询,而根域名服务器和顶级域名服务器都是迭代查询

递归查询:当DNS服务器无法获得IP时,将请求转发到下一级,将下一级的回复转发给请求者

迭代查询:当DNS服务器先向根域名服务器发起查询,根据回复,DNS服务器再向下一级DNS服务器发起查询,直到获得IP

DNS解析过程

  • 浏览器检查自身DNS缓存,没有则交付操作系统进行解析

  • 操作系统检查hosts文件

  • 向本地网卡指定的DNS服务器发起查询,DNS服务器一般是非官方的,本身它会对查找的域名解析结果进行缓存

  • 进行递归查询

使用DNS可以实现基于域名的负载均衡

HTTP流程

  1. TCP三次握手

  2. 浏览器发送HTTP请求报文

  3. Web服务器接收后回复ACK

  4. Web服务器发送HTTP响应报文

  5. 浏览器接收后回复ACK

  • 如果不知道IP地址,就要用DNS协议先解析得到IP地址

  • 为了减少响应时间,整个过程中的每一个环节都会有缓存,比如CDN

HTTP报文

  • 起始行(start line):描述请求或响应的基本信息

  • 头部字段(header):使用key-value形式更详细地说明报文

  • 消息正文(body):实际传输的数据

起始行和头部字段合称为请求头或者响应头,消息正文又称为实体

HTTP协议规定报文必须有header,但可以没有body,而且在header之后必须要有一个空行

  • 请求行:请求方法,请求目标和版本号,如GET / HTTP/1.1

  • 状态行:版本号,状态码和原因,如HTTP/1.1 200 OK

头部字段

  • key和value之间用:分隔,最后用CRLF换行表示字段结束

  • 字段名不区分大小写,不允许出现空格,可以使用连字符-,但不能使用下划线_

  • 字段名后面必须紧接着:,不能有空格,而:后的字段值前可以有多个空格

  • 字段的顺序无规定

常用头部字段

  • 通用字段:在请求头和响应头里都可以出现

  • 请求字段:仅能出现在请求头里

  • 响应字段:仅能出现在响应头里

  • 实体字段:它实际上属于通用字段,但专门描述body的额外信息

Host:           请求字段,必须出现,告诉服务器这个请求应该由哪个主机来处理
User-Agent:     请求字段,描述发起HTTP请求的客户端
Date:           通用字段,表示HTTP报文创建的时间
Server:         响应字段,告诉客户端当前正在提供Web服务的软件名称和版本号
Content-Length: 表示报文里body的长度
  • 数据类型表示实体数据的内容是什么,使用的是MIME type,相关的头字段是Accept和Content-Type

  • 数据编码表示实体数据的压缩方式,相关的头字段是Accept-Encoding和Content-Encoding

  • 语言类型表示实体数据的自然语言,相关的头字段是Accept-Language和Content-Language

  • 字符集表示实体数据的编码方式,相关的头字段是Accept-Charset和Content-Type

  • Accept等头字段可以用,顺序列出多个可能的选项,还可以用;q=参数来精确指定权重

  • 客户端在请求头里使用Accept等头字段与服务器进行协商,要求服务器返回最合适的数据,服务器用Content等头字段告诉客户端实际发送了什么样的数据

文章福利 Linux后端开发网络底层原理知识学习提升 点击学习资料获取,完善技术栈,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。

HTTP请求方法

HTTP/1.1协议中定义了8种HTTP请求方法

  • GET:获取资源

  • HEAD:获取资源的元信息(不会返回实体数据,只会传回响应头)

  • POST:向资源提交数据,相当于写入或上传数据

  • PUT:类似POST

  • DELETE:删除资源

  • CONNECT:建立特殊的连接隧道

  • OPTIONS:列出可对资源实行的方法

  • TRACE:追踪请求-响应的传输路径

扩展方法

安全:请求方法不会破坏服务器上的资源

幂等:多次执行相同的操作,结果也都是相同的

GET/POST区别

  • 提交方式 GET提交是把请求数据附在URL之后,就是把数据放置在请求行中,以?分割URL和传输数据,多个参数用&连接 POST提交是把提交数据放置在HTTP包的包体中

  • 传输数据的大小 对于GET提交,传输数据会受到URL长度的限制,因为特定的浏览器和服务器对URL长度有限制 对于POST提交,由于不是通过URL传值,理论上数据不受限

  • 安全性 POST的安全性要比GET的安全性高 通过GET提交数据,用户名和密码将明文出现在URL上

PUT/POST区别

POST不是幂等的,PUT是幂等的

  • PUT请求:如果两个请求相同,后一个请求会把第一个请求覆盖掉(PUT用来改资源)

  • POST请求:如果两个请求相同,后一个请求不会把第一个请求覆盖掉(POST用来增资源)

URI相关

URI包含URL和URN

URI本质上是一个字符串,这个字符串的作用是唯一地标记资源的位置或者名字

URI通常由scheme、host:port、path和query四个部分组成,有的可以省略

  • scheme:协议名,表示资源应该使用哪种协议来访问

  • host:port: 表示资源所在的主机名和端口号

  • path:标记资源所在的位置

  • query:表示对资源附加的额外要求,用一个?开始,但不包含? 查询参数query有一套自己的格式,是多个key=value的字符串,这些KV值用字符&连接

URI引入了编码机制,对于ASCII码以外的字符集和特殊字符做一个特殊的操作,把它们转换成与URI语义不冲突的形式,把非ASCII码或特殊字符转换成十六进制字节值,然后前面再加上一个%

HTTP状态码

  • 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作

  • 2××:成功,报文已经收到并被正确处理 200 OK 204 No Content:无内容

  • 3××:重定向,资源位置发生变动,需要客户端重新发送请求 301 Moved Permanently:永久移动 302 Found:临时移动 304 Not Modified:未修改

  • 4××:客户端错误,请求报文有误,服务器无法处理 400 Bad Request:错误请求 403 Forbidden:禁止 404 Not Found:未找到

  • 5××:服务器错误,服务器在处理请求时内部发生了错误 500 Internal Server Error:服务器内部错误 502 Bad Gateway:错误网关 503 Service Unavailable:服务不可用

HTTP特点

  • HTTP是灵活可扩展的

  • HTTP是可靠传输协议

  • HTTP使用了请求-应答模式

  • HTTP本质上是无状态的

HTTP优点和缺点

  • HTTP最大的优点是简单、灵活和易于扩展

  • HTTP是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用Cookie技术来实现有状态

  • HTTP是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听

  • HTTP是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改

  • HTTP的性能不算差,但不完全适应现在的互联网,还有很大的提升空间

HTTP实体数据

MIME type

  • text:文本格式的可读数据,text/html表示超文本文档,text/plain表示纯文本

  • image:图像文件,有image/gif、image/jpeg、image/png等

  • audio/video:音频和视频数据,例如audio/mpeg、video/mp4等

  • application:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释

Encoding type

  • gzip:互联网上最流行的压缩格式

  • deflate:zlib(deflate)压缩格式,流行程度仅次于gzip

  • br:一种专门为HTTP优化的新压缩算法

语言

字符集

HTTP传输大文件

压缩HTML等文本文件是传输大文件最基本的方法

分块传输:把大文件分解成多个小块,把这些小块分批发给浏览器,浏览器收到后再组装复原

  • 使用响应头字段Transfer-Encoding: chunked来表示

  • Transfer-Encoding: chunked和Content-Length这两个字段是互斥的

分块格式:长度头 + 数据块

  • 长度头是以CRLF结尾的一行明文,用16进制数字表示长度

  • 数据块紧跟在长度头后,最后也用CRLF结尾,但数据不包含CRLF

  • 最后用一个长度为0的块表示结束,即"0\r\n\r\n"

范围请求:只获取部分数据,即分块请求,实现视频拖拽或者断点续传

  • 服务器使用字段Accept-Ranges: bytes告知客户端支持范围请求

  • 请求头Range是HTTP范围请求的专用字段,格式是bytes=x-y

  • 服务器收到Range字段后,需要做四件事 检查范围是否合法 如果范围正确,服务器根据Range头计算偏移量,读取文件片段,返回状态码206 Partial Content,表示body只是原数据的一部分 服务器添加响应头字段Content-Range,告诉片段的实际偏移量和资源的总大小,格式是bytes x-y/length 发送数据

HTTP的连接管理

  • 早期的HTTP协议使用短连接,收到响应后就立即关闭连接,效率很低

  • HTTP/1.1默认启用长连接,在一个连接上收发多个请求响应,提高了传输效率 服务器会发送Connection: keep-alive字段表示启用了长连接 报文头里如果有Connection: close就意味着长连接即将关闭

  • 过多的长连接会占用服务器资源,所以服务器会用一些策略有选择地关闭长连接 设置超时时间 设置最大请求数

队头阻塞

  • 队头阻塞与连接长短无关,而是由HTTP基本的请求-应答模型所导致的

  • 队头阻塞问题会导致性能下降,可以用并发连接和域名分片技术缓解

  • 第一种请求方式,单次发送request请求,收到response后再进行下一次请求,效率低效

  • HTTP/1.1提出了管线化(pipelining)技术,就是第二种请求方式,一次性发送多个request请求

  • pipelining在接收response时必须依顺序接收,如果前一个请求遇到了阻塞,后面的请求即使已经处理完毕,仍然需要等待阻塞的请求处理完毕。这种情况就是第三种,这就是队头阻塞(Head of line blocking)

  • HTTP/2提出了多路复用(Multiplexing)技术,将每个request-response拆分为了细小的二进制帧Frame,这样即使一个请求被阻塞了,也不会影响其他请求,如图中第四种情况

HTTP的重定向和跳转

  • 主动跳转和被动跳转(重定向)

  • 重定向是服务器发起的跳转,要求客户端改用新的URI重新发送请求,通常会自动进行,用户无感知

  • 301/302是最常用的重定向状态码,分别是永久重定向和临时重定向

  • 响应头字段Location指示了要跳转的URI,可以用绝对或相对的形式

  • 使用重定向时需要当心性能损耗(一个跳转会有两次请求-应答),还要避免出现循环跳转

HTTP的Cookie机制

无状态优点是服务器没有状态差异,可以很容易地组成集群,而缺点就是无法支持需要记录状态的事务操作

Cookie是客户端保持状态的方法

  • Cookie简单的理解就是存储由服务器发给客户端并由客户端保存的一段字符串。为了保持会话,服务器可以在响应客户端请求时将Cookie字符串放在Set-Cookie下,客户机收到Cookie之后保存这段字符串,之后再请求时候带上Cookie就可以被识别

Session是服务器保持状态的方法

  • Session保存在服务器上,每个用户有一个独一无二的Session ID作为Session文件的Hash键,通过这个值可以锁定具体的Session结构的数据,这个Session结构中存储了用户操作行为

  • 当服务器需要识别客户端时就需要结合Cookie了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用Cookie来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在Cookie里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。如果客户端的浏览器禁用了Cookie,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如sid=xxxxx这样的参数,服务端据此来识别用户,这样就可以帮用户完成诸如用户名等信息自动填入的操作了

HTTP的代理服务

  • 代理处于中间层,为HTTP处理增加了更多的灵活性,可以实现负载均衡、安全防护、数据过滤等功能

HTTP的缓存代理

  • 缓存代理是增加了缓存功能的代理服务,缓存源服务器的数据,分发给下游的客户端

HTTPS

通信安全必须同时具备机密性、完整性,身份认证和不可否认这四个特性

  • 机密性:只能由可信的人访问,对其他人不可见

  • 完整性:数据在传输过程中没有被窜改

  • 身份认证:确认对方的真实身份

  • 不可否认:不能否认已经发生过的行为

HTTPS实际上是HTTP over SSL/TLS,让HTTP运行在了安全的SSL/TLS协议上,HTTPS默认端口443

SSL(Secure Sockets Layer),在OSI模型中处于会话层,TLS是SSL的标准化

密码套件:秘钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法

OpenSSL是著名的开源密码学工具包,是SSL/TLS的具体实现

对称加密和非对称加密

对称加密

  • 加密和解密使用同一个秘钥,运算速度快

  • 常用的对称加密算法有AES和ChaCha20

  • 对称加密有一个分组模式的概念,可以用固定长度的秘钥加密任意长度的报文,常用的是GCM、CCM和Poly1305

  • 对称加密无法保证密钥的安全交换

非对称加密

  • 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题

  • 公钥加密后只能用私钥解密,私钥加密后也只能用公钥解密

  • 常用的非对称加密算法有RSA和ECC,RSA基于整数分解的数学难题,ECC基于椭圆曲线离散对数的数学难题,ECC子算法ECDHE用于密钥交换,子算法ECDSA用于数字签名

  • 在速度上,ECC比AES差上好几个数量级

把对称加密和非对称加密结合起来就得到了混合加密,也就是TLS里使用的加密方式

数字签名和证书

对称加密和非对称加密仅仅解决了机密性

摘要算法用来实现完整性,把任意长度的数据映射成固定长度,常用的摘要算法是MD5,SHA-1,SHA-2

摘要算法对输入具有单向性和雪崩效应

  • 不能从摘要逆推出原文

  • 输入的微小不同会导致输出的剧烈变化

真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息和摘要

数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认

数字签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息

公钥的分发需要使用数字证书,必须由CA(Certificate Authority,证书认证机构)的信任链来验证,否则就是不可信的

TLS1.2连接过程

HTTPS协议会先执行TCP握手,然后执行TLS握手,才能建立安全连接

  • 握手的目标是安全地交换对称密钥,需要三个随机数,第三个随机数Pre-Master必须加密传输

  • Hello消息交换随机数,Key Exchange消息发送Pre-Master

  • Change Cipher Spec之前传输的都是明文,之后都是对称密钥加密的密文

HTTPS握手过程

  1. Client Hello:客户端向服务器发送消息,其中包含一个客户端生成的随机数(val1)

  2. Server Hello:服务端响应客户端的请求,其中包含一个服务端生成的随机数(val2)和服务端证书

  3. 客户端请求:客户端验证证书后,从证书取出服务端的公钥,并回复服务端,其中包含一个用公钥加密过的随机数(val3),并通知握手结束

  4. 服务端响应:服务端通过私钥解密随机数(val3),并用三个随机数生成一个对称秘钥,之后传输的数据都用此秘钥加密,并通知握手结束

补充

HTTP/1.0和HTTP/1.1区别

  • HTTP/1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP/1.1默认支持长连接

  • 节约带宽,HTTP/1.1支持只发送header消息(不带body)

  • HTTP/1.0没有HOST域

  • HTTP/1.1使用了pipelining技术

HTTP/1.1和HTTP/2区别

  • HTTP/2使用了多路复用技术,做到同一个连接并发处理多个请求 HTTP/1.1通过建立多个TCP连接,来支持处理更多并发的请求,但是创建TCP连接需要开销

  • HTTP/1.1不支持header数据的压缩 HTTP/2使用HPACK算法对header的数据进行压缩

  • HTTP/2将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码,从而改进传输性能

CGI与环境变量

  • CGI程序 服务器为客户端提供动态服务首先需要解决的是得到用户提供的参数再根据参数信息返回。为了和客户端进行交互,服务器需要先创建子进程,之后子进程执行相应的程序去为客户服务。CGI正是帮助我们解决参数获取、输出结果的 动态内容获取其实请求报文的头部和请求静态数据时完全相同,但请求的资源从静态的HTML文件变成了后台程序。服务器收到请求后fork一个子进程,子进程执行请求的程序,这样的程序称为CGI程序(Python、Perl、C++等均可)。通常在服务器中我们会预留一个单独的目录(cgi-bin)用来存放所有的CGI程序,请求报文头部中请求资源的前缀都是/cgi-bin,之后加上所请求调用的CGI程序即可 所以上述流程就是:客户端请求程序 -> 服务器fork子进程 -> 执行被请求程序。接下来需要解决的问题就是如何获取客户端发送过来的参数和输出信息怎么传递回客户端

  • 环境变量 对CGI程序来说,CGI环境变量在创建时被初始化,结束时被销毁。当CGI程序被HTTP服务器调用时,因为是被服务器fork出来的子进程,所以其继承了其父进程的环境变量,这些环境变量包含了很多基本信息,请求头中和响应头中列出的内容(比如用户Cookie、客户机主机名、客户机IP地址、浏览器信息等),CGI程序所需要的参数也在其中

  • GET方法下参数获取 服务器把接收到的参数数据编码到环境变量QUERY_STRING中,在请求时只需要直接把参数写到URL最后即可,比如http:127.0.0.1:80/cgi-bin/test?a=1&b=2&c=3,表示请求cgi-bin目录下test程序,?之后部分为参数,多个参数用&分割开。服务器接收到请求后环境变量QUERY_STRING的值即为a=1&b=2&c=3 在CGI程序中获取环境变量值的方法是:getenv(),比如我们需要得到上述QUERY_STRING的值,只需要下面这行语句就可以了

char *value = getenv("QUERY_STRING");
  • 之后对获得的字符串处理一下提取出每个参数信息即可

  • POST方法下参数获取 POST方法下,CGI可以直接从服务器标准输入获取数据,不过要先从CONTENT_LENGTH这个环境变量中得到POST参数长度,再获取对应长度内容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值