理解 http 传输过程

理解 http 传输过程

通过TCP、Socket、HTTP 协议来理解 HTTP 传输的整个过程

TCP/IP 协议族

TCP/IP 协议不是指 TCP 和 IP 两种协议,而是指利用 IP 进行通信时所需要用到的协议群的统称。

OSI中的层功能TCP/IP协议族
应用层文件传输,电子邮件,文件服务,虚拟终端TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet
表示层数据格式化,代码转换,数据加密没有协议
会话层解除或建立与别的接点的联系没有协议
传输层提供端对端的接口TCP,UDP
网络层为数据包选择路由IP,ICMP,RIP,OSPF,BGP,IGMP
数据链路层传输有地址的帧以及错误检测功能SLIP,CSLIP,PPP,ARP,RARP,MTU
物理层以二进制数据形式在物理媒体上传输数据ISO2110,IEEE802。IEEE802.2

下面的协议都属于TCP/IP协议族:

  • TCP(Transport Control Protocol)传输控制协议
  • IP(Internetworking Protocol)网间网协议
  • UDP(User Datagram Protocol)用户数据报协议
  • ICMP(Internet Control Message Protocol)互联网控制信息协议
  • SMTP(Simple Mail Transfer Protocol)简单邮件传输协议
  • SNMP(Simple Network manage Protocol)简单网络管理协议
  • FTP(File Transfer Protocol)文件传输协议
  • ARP(Address Resolation Protocol)地址解析协议

其中物理层、数据链路层、网络层、传输层都是由系统提供的能力,我们无法进行处理,也不用太去关心,绝大部分情况下我们都是在应用层对TCP或者UDP进行编程处理。

TCP 编程

对TCP编程我们一般使用Socket,Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket 包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,通过Socket可以区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

Socket 提供以下接口:

  • socket: 创建socket。
  • bind: 绑定socket到本地地址和端口,通常由服务端调用。
  • listen: 开启监听模式监听端口。
  • accept: 服务器等待客户端连接,一般是阻塞态。
  • connect: 客户端主动连接服务器。
  • send: 发送数据。
  • recv: 接受数据。
  • closesocket: 关闭socket。

image.png

可以简单理解为通过Socket编程通过TCP协议和另一个IP主机进行数据的交互,在TCP上传输的数据都是明文的。

三次握手和四次挥手在 Socket 之下,不属于 Socket 的内容。

HTTP 协议

HTTP 协议是在TCP 协议之上建立的,客户端和服务端在通过TCP协议建立连接后,通过明文传输HTTP报文,传输结束后断开TCP 。

HTTP 报文在TCP上是明文传输的,在TCP层可以拦截HTTP请求的报文,任何一个路由器节点可以查看、修改、拦截HTTP请求。

HTTP 协议的请求报文和响应报文的结构基本相同,由四部分组成:

image.png

  1. 请求行(request line):由请求方法、URL(包含Query参数)和HTTP协议版本组成。
  2. 头部(header):由多个key-value值组成。
  3. 空行:请求报文使用空行将请求头部和请求数据分隔。
  4. 实体:POST、PUT 等方法可以携带 Body。

请求行

请求报文里的起始行也就是请求行(request line),它简要地描述了客户端想要如何操作服务器端的资源。

请求行由三部分构成:

  1. 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
  2. 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
  3. 版本号:表示报文使用的 HTTP 协议版本。

这三个部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。

image.png

POST /search?q=http HTTP/1.1

状态行

响应报文里的起始行,在这里它不叫“响应行”,而是叫“状态行”(status line),意思是服务器响应的状态。

比起请求行来说,状态行要简单一些,同样也是由三部分构成:

  1. 版本号:表示报文使用的 HTTP 协议版本;
  2. 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
  3. 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。

image.png

HTTP/1.1 200 OK

头部字段

请求行或状态行再加上头部字段集合就构成了 HTTP 报文里完整的请求头或响应头:

image.png

image.png

请求头和响应头的结构是基本一样的,唯一的区别是起始行。

头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。比如在“Host: 127.0.0.1”这一行里 key 就是“Host”,value 就是“127.0.0.1”。

HTTP 头字段非常灵活,不仅可以使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头,这就给 HTTP 协议带来了无限的扩展可能。

不过使用头字段需要注意下面几点:

  • 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
  • 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;
  • 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;
  • 字段的顺序是没有意义的,可以任意排列不影响语义;
  • 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

实体

实体在请求里是POST、PUT等请求body里携带的内容,大部分情况下是 JSON,也可以是 Protobuf 等进行编码过的内容。

在响应里就是响应的实际内容,例如GET请求返回的HTML页面,或者JSON数据等等。

HTTPS

上面可以看到 HTTP 报文就是一个文本协议,可以看成一个字符串,这个字符串在 TCP 上是进行明文传输的,非常的不安全,所以为了数据安全传输,需要对这个字符串进行加密传输,这个加密的方法就是 HTTPS。

在请求发送时,还是正常的HTTP报文,然后通过 TLS协商密钥进行加密,传输到服务器上时再通过 协商密钥 进行解密。响应数据一样的加密解密。

具体HTTPS的过程可以看我的博客:HTTPS小故事

完整过程大致如下

  1. 客户端和服务器通过TCP三次握手建立连接。
  2. 客户端和服务器通过Socket发送和接收数据进行TLS握手生成协商密钥
  3. 客户端使用协商密钥HTTP请求报文进行加密。
  4. Socket通过TCP把加密后的HTTP请求报文发送到服务器。
  5. 服务器通过Socket获取加密后的HTTP请求报文
  6. 服务器解密数据获取HTTP请求报文,进行解析。
  7. 服务器处理HTTP请求报文,生成一个HTTP响应报文
  8. 服务器使用协商密钥HTTP响应报文进行加密。
  9. 服务器使用Socket通过协商密钥加密后的HTTP响应报文发送到客户端。
  10. 客户端收到加密数据进行解密,获取HTTP响应报文
  11. 客户端和服务器通过TCP四次挥手取消连接。

参考

  1. 网络篇——七层协议、四层协议、TCP、HTTP、SOCKET、长短连接
  2. tcp, socket与http之间有什么关联?
  3. Socket接口使用方法
  4. 使用 Go 进行 Socket 编程 | 始于珞尘
  5. HTTP报文格式详解
  6. HTTP报文格式简介

Did you find this article valuable?

Support MervynZhang by becoming a sponsor. Any amount is appreciated!