搞这么久的开发你真的知道HTTP吗

595 阅读14分钟

目录

1、HTTP协议

1.1、什么是HTTP协议

HTTP协议(HyperText Transfer Protocol,超文本传输协议),是一种应用层协议,常用于计算机之间的通信。它最初是为了在万维网上进行通信而开发的,现在已经成为互联网上最为广泛使用的协议之一。

HTTP协议通常基于TCP/IP协议栈,使用客户端-服务端模型,通过请求和响应来进行通信。客户端发送HTTP请求到服务器,服务器向客户端返回HTTP响应,包括状态码、响应头和响应体等信息。

HTTP协议基于文本格式进行通信,采用请求方法、URL、版本号、请求头、请求体等组成请求,采用状态码、响应头、响应体等组成响应。其中请求方法表示对资源执行的操作类型,常见的有 GET、POST、PUT、DELETE 等;URL 表示请求的资源地址;版本号表示 HTTP 协议的版本号;请求头和响应头包含了关于请求和响应的元数据信息;请求体和响应体包含了具体请求和响应的数据内容。

HTTP协议支持无状态和有状态两种模式。无状态模式下每个请求都是独立的,服务器不会记住之前的请求信息;而有状态模式下服务器可以记录客户端的请求历史和状态信息,从而实现更多的功能和服务。

在实际开发中,我们经常使用工具库和框架来简化HTTP协议的操作,如Spring MVC、Express、axios等。

1.2、HTTP协议组成部分

HTTP(HyperText Transfer Protocol)协议是一种应用层协议,常用于计算机之间的通信。它是构建万维网的基础,也是现代互联网应用最为广泛的协议之一。

HTTP 协议通常基于 TCP/IP 协议栈进行通信,使用客户端-服务端模型,通过请求和响应来进行通信。HTTP 协议主要由请求报文与响应报文组成:


请求报文:包含请求行、请求头部、空行、请求体。

/*请求行:包含了请求方法、URL 和 HTTP 版本号等信息,格式如下:*/
<method> <request-url> HTTP/<version>
/*请求头部:包含了请求报文的相关信息,例如 User-Agent、Host 等,格式如下:*/
<header-name>: <header-value>=
/*空行:用于分隔请求头部和请求体,格式为一个空行。*/
/*请求体:包含了请求参数和数据,格式根据 Content-Type 的不同而不同。*/

其中HTTP请求体通常用于传输客户端向服务器提交的数据,例如表单数据、JSON数据等。HTTP请求体的主要参数有:

  • Content-Type:表示请求体的编码格式和内容类型。
  • Content-Length:表示请求体的长度,单位为字节。
  • 请求体的实际数据:根据Content-Type的不同,请求体可以包含不同类型的数据,例如application/json、application/x-www-form-urlencoded等。

以下是一个以POST方式提交JSON数据的HTTP请求的示例代码:

POST /api/user HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 38

{"username":"Alice", "password":"123456"}

该请求将用户信息以JSON格式发送给服务器,其中Content-Type为application/json,Content-Length为38个字节,请求体为{"username":"Alice", "password":"123456"},表示用户名为Alice,密码为123456。


响应报文: 包含响应状态行、响应头部、空行、响应体。

/*响应状态行:包含了 HTTP 版本号、状态码和状态描述信息,格式如下:*/
HTTP/<version> <status-code> <reason-phrase>
/*响应头部:包含了响应报文的相关信息,例如 Content-Type、Content-Length 等,格式如下:*/
<header-name>: <header-value>
/*空行:用于分隔响应头部和响应体,格式为一个空行。*/
/*响应体:包含了服务器返回的数据,格式根据 Content-Type 的不同而不同。*/

其中HTTP响应体用于返回服务器处理后的结果数据,例如HTML页面、JSON数据等。HTTP响应体的主要参数有:

  • Content-Type:表示响应体的编码格式和内容类型。
  • Content-Length:表示响应体的长度,单位为字节。
  • 状态码:表示服务器处理请求的结果状态,例如200表示成功,404表示未找到资源等。
  • 响应头:包含了一些有关响应的元数据信息,例如Last-Modified、Expires、Cache-Control等。
  • 响应体的实际数据:根据Content-Type的不同,响应体可以包含不同类型的数据,例如text/html、application/json等。

以下是一个以JSON格式返回用户信息的HTTP响应的示例代码:

HTTP/1.1 200 OK
Date: Mon, 01 Jan 2022 00:00:00 GMT
Content-Type: application/json
Content-Length: 38

{"username":"Alice", "age":25, "gender":"F"}

该响应返回了一个状态码为200的成功结果,Content-Type为application/json,Content-Length为38个字节,响应体为{"username":"Alice", "age":25, "gender":"F"},表示用户名为Alice,年龄为25岁,性别为女。

HTTP 协议支持无状态和有状态两种模式。无状态模式下每个请求都是独立的,服务器不会记住之前的请求信息;而有状态模式下服务器可以记录客户端的请求历史和状态信息,从而实现更多的功能和服务。

2、HTTP协议等于TCP协议吗

2.1、什么是TCP协议

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠的传输层协议。它在计算机网络中扮演着非常重要的角色,负责实现各种应用程序之间的数据传输、错误检测和纠正等功能。

TCP 协议主要有以下特点:

  • 面向连接:在发送数据前,需要通过三次握手建立连接,确保通信双方已经准备好进行数据传输。
  • 可靠性:采用数据包确认、超时重传等机制来保证数据的正确传输和接收,避免数据丢失或损坏。
  • 按序传输:每个 TCP 报文都带有一个唯一的序列号,用于保证数据按照正确的顺序进行传输和接收。
  • 流控制:通过滑动窗口机制,调整发送速率和接收速率,以适应不同的网络环境和带宽限制。
  • 拥塞控制:通过慢启动、拥塞避免、快速恢复等机制,调整数据流量,防止网络拥堵。
  • 多路复用:可以同时处理多个连接,提高网络利用率和效率。

TCP 协议通常作为传输层协议使用,在 OSI(Open System Interconnection,开放式系统互连)模型中处于第四层。它可以通过 IP(Internet Protocol,互联网协议)协议来进行网络传输,并为上层应用程序提供可靠的数据传输服务。

在实际开发中,TCP 协议被广泛应用于各种场景,例如 Web 浏览器、文件传输、电子邮件、远程登录等。

2.2、HTTP协议和TCP协议一样吗

HTTP 协议和 TCP 协议是两个不同的协议,它们在 OSI(Open System Interconnection,开放式系统互连)模型中处于不同的层级。

TCP 协议是传输层协议,它提供了可靠的、面向连接的数据流传输服务。TCP 协议采用三次握手建立连接,四次挥手断开连接的机制来保证数据传输的可靠性、完整性和顺序性,可以支持大规模数据传输和高速网络环境下的稳定连接。

HTTP 协议是应用层协议,它基于 TCP 协议之上,使用请求/响应模型进行通信,主要用于 Web 应用程序之间的数据交换。HTTP 协议定义了客户端和服务器之间如何格式化和传输请求和响应消息,包括报文格式、请求方法、状态码、头部字段等等。

因此,HTTP 协议并不等于 TCP 协议。HTTP 协议是基于 TCP 协议之上的一个应用层协议,使用 TCP 协议提供的可靠性和稳定性来保证 HTTP 数据的正确传输。HTTP 协议与 TCP 协议之间的关系就像是邮局与快递公司之间的关系一样,HTTP 协议是高层次的应用协议,而 TCP 协议则是低层次的传输协议。

3、面试中常问的三次握手和四次挥手又是什么

3.1、谁在握手和挥手

HTTP 协议本身并不需要进行握手,因为它是基于 TCP/IP 协议栈上的应用层协议,而 TCP 协议需要进行三次握手建立连接。

因此,这个问题其实涉及到了 TCP 的连接管理过程中所谓的“三次握手”和“四次挥手”。

3.2、TCP三次握手

TCP三次握手是指在建立TCP连接时,客户端和服务器之间通过交换三个数据包来确认彼此的身份和建立可靠的连接。三次握手的目的是防止已失效的连接请求报文段突然又传送到了服务器,因而产生错误。

当客户端发送一个请求时,它需要建立与服务器之间的一个 TCP 连接。在这个过程中,会先进行三次握手来确认连接的建立。具体流程如下:

  • 客户端向服务器发送 SYN 报文,表示请求建立连接,并随机生成一个 ISN(Initial Sequence Number)作为序列号。
SYN_SENT:
Client ------- SYN ------> Server
  • 服务器收到 SYN 报文后,回复一个 SYN+ACK 报文,表示同意建立连接,并也随机生成一个 ISN 和 ACK 序列号,ACK 序列号为客户端的 ISN 值 +1。
SYN_RCVD:
Client <------ SYN+ACK ---- Server
  • 客户端再发一个 ACK 报文,表示确认收到 SYN+ACK 报文,同时也随机生成一个 ACK 序列号,为服务器的 ISN 值 +1。
STABLISHED:
Client ------- ACK -------> Server

客户端向服务器发送 SYN 报文,表示请求连接,至此,三次握手完成,连接建立成功。

import java.net.*;

public class Client {
    public static void main(String[] args) throws Exception {
        String ip = "127.0.0.1";
        int port = 8080;

        Socket socket = new Socket(ip, port);

        // 发送 SYN 报文
        OutputStream out = socket.getOutputStream();
        out.write(new byte[]{0x00, 0x01});

        // 接收 SYN+ACK 报文
        InputStream in = socket.getInputStream();
        byte[] data = new byte[1024];
        in.read(data);

        // 发送 ACK 报文
        out.write(new byte[]{0x00, 0x01});

        socket.close();
    }
}

在上述 Java 代码中,我们使用了 java.net 包中的 Socket 类创建了一个客户端套接字,通过 connect() 方法连接到指定的服务器地址和端口。然后按照上述三次握手的流程,分别发送 SYN、SYN+ACK 和 ACK 报文,完成连接建立过程。

3.3、TCP四次挥手:

当客户端发送完请求并接收到了所有响应后,需要断开与服务器之间的连接。在断开连接时,会先进行四次挥手,确保连接的正常关闭。具体流程如下:

  • 客户端向服务器发送 FIN 报文,表示要关闭连接。此时,客户端不能再发送数据了。
FIN_WAIT_1:
Client ------- FIN ------> Server
  • 服务器收到 FIN 报文后,回复一个 ACK 报文表示准备关闭连接,并等待所有的数据都发送完成。
CLOSE_WAIT:
Client <------ ACK ------ Server
  • 数据发送完成后,服务器向客户端发送 FIN 报文,表示同意关闭连接。
LAST_ACK:
Client <------ FIN ------ Server
  • 客户端收到 FIN 报文后,回复一个 ACK 报文表示确认收到,并等待两倍的最长报文段生命期(即两倍的最大网络延迟时间)后,如果没有收到服务器的新报文,就认为连接已经正常关闭。
CLOSED:
Client ------- ACK ------> Server

客户端向服务器发送 FIN 报文,表示请求关闭 TCP 连接,至此,四次挥手完成,连接断开成功。

import java.net.*;

public class Client {
    public static void main(String[] args) throws Exception {
        String ip = "127.0.0.1";
        int port = 8080;

        Socket socket = new Socket(ip, port);

        // 发送 FIN 报文
        OutputStream out = socket.getOutputStream();
        out.write(new byte[]{0x00, 0x01});

        // 接收 ACK 报文
        InputStream in = socket.getInputStream();
        byte[] data = new byte[1024];
        in.read(data);

        // 发送 ACK 报文
        out.write(new byte[]{0x00, 0x01});

        // 接收 FIN 报文
        in.read(data);

        // 发送 ACK 报文
        out.write(new byte[]{0x00, 0x01});

        socket.close();
    }
}

在上述 Java 代码中,我们先发送 FIN 报文来请求关闭 TCP 连接,然后等待服务器回复的 ACK 报文,并再次发送 ACK 报文来确认关闭请求。接着,我们等待服务器发送 FIN 报文来准备关闭 TCP 连接,最后再次发送 ACK 报文来确认关闭请求。此时,TCP 连接已经完全关闭。

总之,三次握手和四次挥手是 TCP 连接管理过程中的关键步骤,确保了通信的可靠性和完整性。HTTP 请求和响应都是基于 TCP 连接进行的,因此它们也会遵循这些步骤来建立和关闭连接。

3.4、TCP三次握手的重要性

TCP三次握手的过程是建立TCP连接的必要步骤,它的重要性体现在以下几个方面:

  • 防止已失效的连接请求报文段突然又传送到了服务器,因而产生错误。
  • 确认双方的身份,防止TCP连接被第三方攻击者伪造。
  • 确保双方的初始序列号和窗口大小都被正确地设置,以确保数据传输的可靠性。

TCP三次握手是建立TCP连接的必要步骤,它通过交换三个数据包来确认彼此的身份和建立可靠的连接。三次握手的过程包括客户端向服务器发送连接请求报文段、服务器向客户端发送确认请求报文段、客户端向服务器发送确认报文段。TCP三次握手的重要性体现在防止已失效的连接请求报文段突然又传送到了服务器、确认双方的身份、确保双方的初始序列号和窗口大小都被正确地设置等方面。

3.5、TCP三次握手中存在的漏洞

TCP 三次握手是一种建立 TCP 连接的过程,包括客户端向服务器发送 SYN 报文、服务器回复 SYN+ACK 报文和客户端回复 ACK 报文。在这个过程中,存在多种漏洞和攻击方式。

3.5.1、SYN 攻击

SYN 攻击是针对 TCP 协议中的半连接状态(SYN_RCVD)进行攻击的一种方式,通过向目标服务器发送大量伪造的 SYN 报文,填满服务器的连接队列,从而导致正常用户无法建立 TCP 连接。

解决方案: (1)增大服务器的连接队列长度,以容纳更多的半连接请求。 (2)启用 SYN Cookies 机制,将部分连接信息存储在 Cookie 中,减轻服务器负担。 (3)使用防火墙或 IDS 等安全设备,进行流量监测和过滤。

3.5.2、TCP 连接劫持

TCP 连接劫持是指攻击者利用 TCP 连接漏洞,篡改数据传输或欺骗服务器进行操作的行为。

解决方案: (1)在 TCP 报文中增加数字签名或 Hash 算法等验证机制,防止篡改和欺骗操作。 (2)更新系统补丁,修复已知的 TCP 连接漏洞。

3.5.3、SYN+ACK 攻击

SYN+ACK 攻击是针对 TCP 半连接状态下的服务器进行攻击,攻击者伪造源地址发送大量 SYN+ACK 报文,欺骗服务器建立连接,从而消耗服务器资源。

解决方案: (1)增加 TCP 连接数限制、超时断开等机制,防止恶意连接占用服务器资源。 (2)使用防火墙或 IDS 等安全设备,进行流量监测和过滤。

3.5.4、数据注入攻击

数据注入攻击是指攻击者利用 TCP 连接漏洞,将恶意代码或数据注入服务器或客户端进行攻击的行为。

解决方案: (1)使用加密协议(如 SSL/TLS)保护传输数据的安全性,避免数据注入攻击。 (2)在应用程序中增加限流、验证码等机制,减少恶意请求的影响。 (3)更新系统补丁,修复已知的 TCP 连接漏洞。

3.5.5、重放攻击

重放攻击是指攻击者通过记录 TCP 通信过程中的报文,重复发送或篡改报文,导致重复或错误的操作。

解决方案: (1)在 TCP 报文中增加数字签名或 Hash 算法等验证机制,防止重复或篡改操作。 (2)更新系统补丁,修复已知的 TCP 连接漏洞。

总之,在实际开发中,我们需要关注和防范各种网络攻击,保障应用程序的安全和稳定运行。同时,还需要定期更新系统补丁、强化网络设备管理等方面来提高网络安全性。