网络编程—应用层HTTP协议

一、引言

每天打开浏览器刷网页、登录账号、下载文件,这些看似稀松平常的操作背后,都有一个默默无闻的协议在支撑------它就是HTTP。作为应用层最重要的协议之一,HTTP可以说是整个Web世界的基石。

很多同学在学习计算机网络的时候,总觉得HTTP"很简单"------++不就是请求响应吗?不就是GET和POST吗?但真到了面试被问起"GET和POST到底有什么本质区别"、"HTTP长连接和短连接的区别"、"Cookie和Session是怎么工作的++ "这些问题时,往往又答得支支吾吾,知其然而不知其所以然。

这篇文章将从协议格式入手,逐层拆解HTTP的核心机制,不仅会讲清楚"是什么",更会解释"为什么"。最后我们还会用C语言从零实现一个最简单的HTTP服务器,只有亲手写过一遍,才能真正理解协议的本质。


二、HTTP协议

HTTP的全称是HyperText Transfer Protocol****,超文本传输协议。这里的"超文本"指的不仅仅是文本,还包括HTML、图片、音频、视频、CSS等各种资源。它定义了客户端和服务器之间通信的格式和规则,使得不同厂商开发的浏览器和服务器能够互相通信。

2.1 特点

HTTP协议有两个重要的特性,也是面试经常考察的点:

1. 无连接

HTTP早期版本采用的是"请求-应答"模式,每次连接只处理一个请求。服务器处理完客户端的请求并收到应答后,就会断开连接。

这种设计在早期互联网内容简单、网页只有纯文本的时候是足够的,但随着网页内容越来越丰富,一个页面可能包含几十上百个资源,每次都要重新建立TCP连接的开销就变得难以接受了。所以HTTP/1.1引入了长连接机制,这个后面会详细讲。

2. 无状态

HTTP协议本身不会对请求和响应之间的通信状态进行保存。也就是说,服务器不知道客户端之前发过什么请求,每一个请求都是完全独立的。

这个特性有好有坏:好处是服务器不需要维护状态,实现简单,扩展性好;

坏处是如果需要保持用户登录状态、购物车这类功能,就需要额外的机制(Cookie和Session)来实现。

很多人会把"无连接"和"无状态"搞混。简单来说:无连接是指连接会不会复用的问题,无状态是指服务器记不记得你的问题。这是两个完全不同的维度。

2.2 通信模型

HTTP永远是客户端发起请求,服务器回送响应。服务器永远不会主动给客户端发消息,这是一个非常重要的模型。

这种请求-响应模型决定了HTTP天然是"拉"模式的协议,客户端想要什么就主动去拉。如果需要实现服务器主动推送,就需要WebSocket或者HTTP/2的Server Push这类技术了。


三、URL

我们平时说的"网址",其实就是URL(统一资源定位符)。URL是互联网上标准资源的地址,它告诉浏览器资源在哪里,以及用什么方式去访问。一个完整的URL结构如下图所示:

我们来逐一拆解每个部分:

  • 协议方案名 :也就是访问资源使用的协议,最常见的是http和https,还有ftp、file等其他协议。

  • 登录信息 :这部分现在已经很少见了,格式是 user:pass@ ,用来指定用户名和密码进行认证,因为安全性问题基本被淘汰了。

  • 服务器地址:可以是域名,也可以是IP地址。

  • 服务器端口号:如果是协议默认端口可以省略,HTTP默认80,HTTPS默认443。

  • 带层次的文件路径:服务器上资源的路径,对应服务器上的文件或者路由。

  • 查询字符串 :以 ? 开头,以 &分隔的键值对,用来给服务器传递参数,比如 ?uid=1。

  • 片段标识符 :以 # 开头,用来定位页面内的某个位置,比如锚点,这部分是不会发送给服务器的,只有浏览器自己处理。

3.1 urlencode与urldecode

不知道大家有没有注意过,当你在百度搜索 "C++" 的时候,地址栏里显示的是 "c%2B%2B" 而不是直接显示"C++"。这是为什么呢?

因为像 /、?、:、@、=、&、+这些字符,在URL里是有特殊含义的。如果参数里本身就包含这些字符,就会产生歧义。比如你想传一个参数 "a=1&b=2" 作为值,那里面的&就会被当成参数分隔符。这时候就需要对特殊字符进行转义,也就是urlencode。

转义规则很简单:将需要转码的字符转为UTF-8编码的16进制,然后每两位前面加一个%。比如:

  • "+"的ASCII码是43,16进制是2B,所以转义后是%2B

  • 空格的ASCII码是32,16进制是20,所以转义后是%20,或者也可以编码成+

  • 中文的话会先转成UTF-8编码,每个字节都加%,比如"你"的UTF-8编码是E4 BD A0,所以转义后是%E4%BD%A0

*urldecode就是urlencode的逆过程,服务器收到转义后的字符串,会自动还原成原来的字符。*各种编程语言都提供了对应的urlencode和urldecode函数,平时我们不需要自己手动实现,但一定要知道有这么回事。


四、HTTP请求报文

HTTP是一个文本协议,也就是说它的报文是纯ASCII文本,不是二进制的,这也是为什么我们可以直接用telnet或者nc去连接HTTP服务器,手动输入请求就能拿到响应。一个标准的HTTP请求报文由四部分组成:请求行、请求报头、空行、请求正文**。**

我们来看一个真实的POST请求例子,这是从西安交通大学就业网抓包拿到的登录请求:

4.1 请求行

请求行是请求的第一行,格式是:请求方法 + 空格 + URL + 空格 + HTTP版本 + 换行符

比如上面的例子中,请求方法是POST,URL是系统登录---西安交通大学就业管理服务平台,HTTP版本是1.1。

4.2 请求报头

请求行之后就是请求报头,是一系列键值对,格式是 Key: Value,每一对之间用\r\n分隔。这些头部信息告诉服务器关于客户端和请求的各种元信息:

  • Host:指定要访问的服务器主机名和端口,这个在HTTP/1.1里是必须的,因为一台服务器上可能部署多个网站,需要靠Host来区分

  • Content-Length:请求正文的长度,单位是字节。服务器根据这个值来确定要读取多少字节的正文

  • Content-Type:请求正文的数据格式,比如application/x-www-form-urlencoded表示是表单数据,application/json表示是JSON数据

  • User-Agent:客户端的身份信息,告诉服务器客户端是什么浏览器、什么操作系统

  • Cookie:客户端存储的Cookie信息,用来维持状态

  • Referer:这个请求是从哪个页面跳转过来的

  • Accept:客户端能接受哪些类型的响应内容

  • Accept-Encoding:客户端支持哪些压缩算法,比如gzip、deflate

  • Accept-Language:客户端偏好的语言

  • Connection:连接管理,keep-alive表示希望复用长连接

4.3 空行

请求报头结束之后,会有一个空行,这个空行非常重要,它告诉服务器:"头部到此为止了,后面的就是正文了"。服务器解析请求的时候,就是读到空行就知道头部结束了。

4.4 请求正文

空行之后就是请求正文了。GET请求的正文一般是空的,因为参数都放在URL的查询字符串里了。

POST请求的参数一般放在正文里。

很多初学者会问:GET请求能不能带Body?其实规范上并没有禁止GET带Body,但HTTP标准没有定义GET请求的Body应该怎么处理,很多服务器、代理、CDN都会直接忽略GET请求的Body,所以实际开发中永远不要给GET请求加Body,这是约定俗成的规范。


五、HTTP响应报文

服务器收到请求并处理之后,会返回HTTP响应报文。响应报文的结构和请求非常类似,也是四部分:状态行、响应报头、空行、响应正文。

结构 内容 说明
状态行 HTTP版本 + 空格 + 状态码 + 空格 + 状态码描述 + 换行符 比如HTTP/1.1 200 OK
响应报头 Key: Value + 换行符 和请求头类似,是服务器返回的元信息
响应报头 Key: Value + 换行符 和请求头类似,是服务器返回的元信息
响应报头 ... + 换行符 和请求头类似,是服务器返回的元信息
空行 换行符 分隔头部和正文
响应正文 DATA 实际返回的数据,可能是HTML、JSON、图片等

响应案例:

5.1 状态行

状态行是响应的第一行,格式是:HTTP版本 + 空格 + 状态码 + 空格 + 状态码描述 + 换行符

状态码是三位数字,告诉客户端请求处理的结果。状态码描述只是给人看的,程序只看状态码。比如200 OK,404 Not Found这些都是常见的状态码,后面会详细讲。

5.2 响应报头

响应报头也是键值对,和请求头类似,但字段不太一样。常见的响应头有:

  • Content-Type:响应正文的类型,比如text/html是HTML页面,application/json是JSON数据,image/jpeg是JPEG图片

  • Content-Length:响应正文的长度,如果是分块传输就没有这个字段

  • Content-Encoding:正文使用的压缩算法,比如gzip

  • Server:服务器软件信息,比如nginx、Apache

  • Set-Cookie:让浏览器设置Cookie

  • Location:配合3xx状态码做重定向

  • Cache-Control:缓存控制

5.3 空行和响应正文

和请求一样,空行用来分隔头部和正文。空行之后就是实际返回的数据,可能是HTML页面、JSON、图片等等。浏览器拿到正文之后,会根据Content-Type来决定怎么渲染这个内容。


六、HTTP请求方法

HTTP定义了很多请求方法,用来表明对资源要做什么操作。

HTTP/1.0定义了GET、POST、HEAD三种方法,HTTP/1.1又新增了OPTIONS、PUT、DELETE、TRACE、CONNECT五种方法。我们最常用的就是GET和POST,其他方法了解即可。

6.1 GET方法

用途:用于请求URL指定的资源。

示例:GET /index.html HTTP/1.1

特性:指定资源经服务器端解析后返回响应内容。

form表单HTML 表单 | 菜鸟教程

复制代码
std::string GetFileContentHelper(const std::string &path)
{
    // 一份简单的读取二进制文件的代码
    std::ifstream in(path, std::ios::binary);
    if (!in.is_open())
        return "";
    in.seekg(0, in.end);
    int filesize = in.tellg();
    in.seekg(0, in.beg);
    std::string content;
    content.resize(filesize);
    in.read((char *)content.c_str(), filesize);
    // std::vector<char> content(filesize);
    // in.read(content.data(), filesize);
    in.close();
    return content;
}

6.2 POST方法

用途:用于传输实体的主体,通常用于提交表单数据。

示例:POST /submit.cgi HTTP/1.1

特性:可以发送大量的数据给服务器,并且数据包含在请求体中。

form表单HTML 表单 | 菜鸟教程

6.3 区别

这是面试最常考的问题之一,很多人只会背"GET参数在URL,POST参数在Body"、"GET比POST安全"这种表面答案,但其实这都不是本质区别。我们来从多个角度对比一下:

对比维度 GET POST
语义 获取/查询资源(只读) 提交/创建/修改资源(会改变服务器状态)
幂等性 幂等(多次请求结果相同) 非幂等(多次提交可能产生多个资源,比如重复下单)
安全性 安全(不会改变服务器状态) 不安全(会修改服务器上的资源)
参数位置 URL查询字符串 请求正文
参数长度 受URL长度限制(一般几KB) 理论上无限制
缓存 可以被浏览器缓存、收藏为书签 不会被缓存,不能收藏为书签
数据包 一般一个TCP数据包发完(请求头+数据一起发) 可能分两个数据包:先发请求头,服务器返回100 Continue再发正文
编码类型 application/x-www-form-urlencoded 支持多种编码(form-data、json等)

关于"POST比GET安全"这个说法是不准确的。POST的参数在Body里,不会直接显示在地址栏、历史记录、服务器日志里。HTTP是明文传输的,不管是GET还是POST,抓包都能直接看到参数。想要真正安全,必须用HTTPS加密。

6.4 其他方法

6.4.1 PUT方法

用途:用于传输文件,将请求报文主体中的文件保存到请求URL指定的位置。

示例:PUT /example.html HTTP/1.1

特性:不太常用,但在某些情况下,如RESTful API中,用于更新资源。

6.4.2 HEAD方法

用途:与GET方法类似,但不返回报文主体部分,仅返回响应头。

示例:HEAD /index.html HTTP/1.1

特性:用于确认URL的有效性及资源更新的日期时间等。

复制代码
# curl -i 显示响应头和响应体
$ curl -i www.baidu.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 2381
Content-Type: text/html
Date: Sun, 16 Jun 2024 08:38:04 GMT
Etag: "588604dc-94d"
Last-Modified: Mon, 23 Jan 2017 13:27:56 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<!DOCTYPE html>
...

# 使用HEAD方法,只会返回响应头
$ curl --head www.baidu.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 277
Content-Type: text/html
Date: Sun, 16 Jun 2024 08:43:38 GMT
Etag: "575e1f71-115"
Last-Modified: Mon, 13 Jun 2016 02:50:25 GMT
Pragma: no-cache
Server: bfe/1.0.8.18

6.4.3 DELETE方法

用途:用于删除文件,是PUT的相反方法。

示例:DELETE /example.html HTTP/1.1

特性:按请求URL删除指定的资源。

6.4.4 OPTIONS方法

用途:用于查询针对请求URL指定的资源支持的方法。

示例:OPTIONS * HTTP/1.1

特性:返回允许的方法,如GET、POST等。


七、HTTP状态码

状态码是服务器对请求的回应,用三位数字表示。第一位数字定义了响应的类别,一共分为5大类:

我们不需要记住所有状态码,但常见的一定要熟悉,这不仅是面试考点,也是开发中排查问题的基础。

7.1 常见状态码

(1) 2xx 成功类

  • 200 OK:最常见的状态码,表示请求成功,正常返回了数据。

  • 201 Created:请求成功并且服务器创建了新的资源,一般在POST创建资源时返回。

  • 204 No Content:请求成功,但没有返回任何内容。比如删除操作成功后,不需要返回什么数据,就可以返回204。

(2)3xx 重定向类

  • 301 Moved Permanently:永久重定向。资源被永久移动到了新位置,搜索引擎会更新索引,浏览器会缓存这个重定向。

  • 302 Found:临时重定向。资源临时在别的位置,以后还可能变。

  • 304 Not Modified:资源未修改,客户端可以使用本地缓存。这是浏览器缓存机制的重要部分,。

  • 307 Temporary Redirect:和302类似,也是临时重定向,但区别是307不允许改变请求方法。

这里301和302的区别:

状态码 重定向类型 是否缓存 请求方法是否改变 典型场景
301 永久重定向 浏览器会永久缓存 可能改变(POST变GET) 网站换域名、HTTP升级HTTPS
302 临时重定向 不缓存 可能改变(POST变GET) 登录后跳转首页、临时维护页面
307 临时重定向 不缓存 不改变 需要保持POST请求的场景
308 永久重定向 浏览器缓存 不改变 需要保持请求方法的永久重定向

不管是301还是302,都需要配合Location响应头来告诉浏览器要跳转到哪个地址。比如:

复制代码
HTTP/1.1 302 Found
Location: https://www.new-url.com/login
Content-Length: 0

(3)4xx 客户端错误类

  • 400 Bad Request:请求报文有语法错误,服务器无法理解。比如参数格式不对、JSON解析失败。

  • 401 Unauthorized:未认证,需要登录才能访问。注意这个是"未认证"而不是"未授权",名字起得有点误导。

  • 403 Forbidden:服务器拒绝访问,权限不够。比如你登录了普通用户账号,想访问管理员页面,就会返回403。

  • 404 Not Found:最有名的状态码,服务器上找不到你请求的资源。地址写错了、资源被删了都会出现404。

  • 405 Method Not Allowed:请求方法不被允许。比如一个接口只支持POST,你用GET去请求,就会返回405。

(4)5xx 服务器错误类

  • 500 Internal Server Error:服务器内部错误,一般是代码出bug了,比如数据库连不上、空指针异常、程序崩溃。

  • 502 Bad Gateway:网关错误,代理服务器从上游服务器收到了无效的响应。比如Nginx反向代理,后端服务挂了,Nginx就会返回502。

  • 503 Service Unavailable:服务器暂时不可用,一般是维护或者过载了。比如服务器正在重启,或者流量太大扛不住了。

  • 504 Gateway Timeout:网关超时,代理服务器等上游服务器的响应等太久了,超时了。

小技巧:看到状态码先看第一位数字,2开头就是成功,3开头就是跳转,4开头就是客户端的锅,5开头就是服务器的锅。这样排查问题的时候就能快速定位方向了。

八、HTTP Header

Header是HTTP报文的重要组成部分,它携带了很多关键信息。我们不可能记住所有Header,但常用的一定要理解。这里挑最重要的几个详细讲。

8.1 实体相关Header

  • Content-Type:非常重要的Header,指定了Body的数据格式。浏览器会根据这个值来解析Body内容。常见的取值:

    • text/html:HTML文档

    • text/css:CSS样式表

    • application/javascript:JavaScript代码

    • application/json:JSON数据

    • application/x-www-form-urlencoded:普通表单提交的数据,格式和URL查询字符串一样

    • multipart/form-data:包含文件上传的表单数据

    • image/jpeg、image/png:图片资源

  • Content-Length:Body的长度,单位是字节。服务器根据这个值来确定要读取多少数据。

  • Content-Encoding:Body使用的压缩算法,最常见的是gzip。

8.2 请求相关Header

  • Host:HTTP/1.1必须携带的Header,指定请求的主机名和端口。

  • User-Agent:告诉服务器客户端的信息,包括浏览器类型、版本、操作系统等。很多网站会根据UA来判断你是PC还是手机,然后返回不同的页面。

  • Referer:告诉服务器这个请求是从哪个页面跳转过来的。注意这个单词拼错了,正确的拼写应该是Referrer,但是标准写错了,将错就错一直用到现在。

  • Accept:客户端能接受的媒体类型,用q值表示权重,比如q=0.9表示优先级0.9。

  • Accept-Encoding:客户端支持的压缩算法,比如gzip, deflate, br。

  • Accept-Language:客户端偏好的语言,比如zh-CN表示中文,en表示英文。

8.3 连接管理Header

Connection字段用来管理TCP连接是否复用。

  • Connection: keep-alive:告诉对方这个TCP连接不要关闭,后面的请求还要复用这个连接,也就是长连接。HTTP/1.1默认就是长连接。

  • Connection: close:告诉对方请求处理完就关闭连接。HTTP/1.0默认是短连接,每次请求完就关闭。

长连接的好处:长连接只需要建立一次TCP连接,就可以在上面传输多个请求响应,大大减少了握手开销和延迟。

长连接的坏处:服务器要维护大量打开的连接,每个连接都占用文件描述符和内存。所以一般服务器都会配置长连接超时时间。

8.4 其他重要Header

  • Cookie:客户端把Cookie发给服务器,用来维持状态,下一节详细讲。

  • Set-Cookie:服务器让浏览器设置Cookie。

  • Location:配合3xx状态码做重定向,指定目标URL。

  • Cache-Control:控制缓存策略,比如max-age=3600表示缓存3600秒,no-cache表示不缓存。

  • Server:服务器软件信息,比如nginx/1.18.0。


九、实现一个HTTP服务器

说一千道一万,不如亲手写一遍。HTTP协议本质上就是TCP连接上传输的符合特定格式的文本,我们完全可以用最基础的Socket API来实现一个最简单的HTTP服务器。

我们用C语言来写,整个服务器代码不到60行,就能在浏览器里显示"hello world"。

cpp 复制代码
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void Usage() {
    printf("usage: ./server [ip] [port]\\n");
}

int main(int argc, char* argv[]) {
    if (argc != 3) {
        Usage();
        return 1;
    }

    // 1. 创建TCP套接字
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket");
        return 1;
    }

    // 2. 绑定IP和端口
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));

    int ret = bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr));
    if (ret < 0) {
        perror("bind");
        return 1;
    }

    // 3. 开始监听
    ret = listen(listen_fd, 10);
    if (ret < 0) {
        perror("listen");
        return 1;
    }

    printf("Server started on http://%s:%s\\n", argv[1], argv[2]);

    // 4. 循环接受连接
    for (;;) {
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len);
        if (client_fd < 0) {
            perror("accept");
            continue;
        }

        // 5. 读取请求(这里简单读取,不做解析)
        char input_buf[1024 * 10] = {0};
        ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);
        if (read_size > 0) {
            printf("[Request]\\n%s\\n", input_buf);
        }

        // 6. 构造HTTP响应
        const char* body = "<h1>hello world</h1>";
        char response[1024] = {0};
        sprintf(response, 
            "HTTP/1.0 200 OK\\r\\n"
            "Content-Type: text/html\\r\\n"
            "Content-Length: %lu\\r\\n"
            "\\r\\n"
            "%s", 
            strlen(body), body
        );

        // 7. 发送响应
        write(client_fd, response, strlen(response));

        // 8. 关闭连接
        close(client_fd);
    }

    close(listen_fd);
    return 0;
}

TCP服务器流程:socket -> bind -> listen -> accept -> read -> write -> close。构造响应字符串的时候要按照HTTP协议格式:状态行 + 响应头 + 空行 + 正文。

我们来编译运行一下:

bash 复制代码
$ gcc server.c -o server
$ ./server 0.0.0.0 9090
Server started on http://0.0.0.0:9090

然后打开浏览器,输入http://127.0.0.1:9090,就能看到页面上显示"hello world"了!同时服务器终端会打印出浏览器发来的请求:


十、HTTP协议演进

HTTP(Hypertext Transfer Protocol,超文本传输协议)作为互联网中浏览器和服务器间通信的基石,经历了从简单到复杂、从单一到多样的发展过程。以下将按照时间顺序,介绍HTTP的主要版本、核心技术及其对应的时代背景。

版本 发布时间 核心特性 解决的痛点
HTTP/0.9 1991年 只支持GET,只有HTML,没有头部,没有状态码 最初只用来传输简单的超文本文档
HTTP/1.0 1996年 增加POST、HEAD方法,有头部,支持多种内容类型,状态码,缓存 网页内容开始丰富,需要传输图片等不同类型资源
HTTP/1.1 1999年 长连接,管道化,Host头,分块传输,更多方法 HTTP/1.0每次请求都新建连接,性能太差
HTTP/2 2015年 二进制分帧,多路复用,头部压缩,服务器推送 HTTP/1.1队头阻塞,头部冗余太大
HTTP/3 2022年 基于QUIC协议(UDP),0-RTT握手,解决TCP队头阻塞 TCP协议本身的队头阻塞问题,握手延迟高

10.1 HTTP/0.9

(1)核心技术

  • 仅支持GET请求方法。

  • 仅支持纯文本传输,主要是HTML格式。

  • 无请求和响应头信息。

(2)时代背景

  1. 1991年,HTTP/0.9版本作为HTTP协议的初始版本,用于传输基本的超文本HTML内容。

  2. 当时的互联网还处于起步阶段,网页内容相对简单,主要以文本为主。

10.2 HTTP/1.0

(1)核心技术

  • 引入POST和HEAD请求方法。

  • 请求和响应头信息,支持多种数据格式。

  • 支持缓存。

  • 状态码、多字符集支持等。

(2)时代背景

  1. 1996年,随着互联网的快速发展,网页内容逐渐丰富,HTTP/1.0版本应运而生。

  2. 为了满足日益增长的网络应用需求,HTTP/1.0增加了更多的功能和灵活性。

  3. 然而,HTTP/1.0的工作方式是每次TCP连接只能发送一个请求,性能上存在一定局限。

10.3 HTTP/1.1

(1)核心技术

  • 引入持久连接,支持管道化)。

  • 允许在单个TCP连接上进行多个请求和响应,提高了性能。

  • 引入分块传输编码。

  • 支持Host头,允许在一个IP地址上部署多个Web站点。

(2)时代背景

  1. 1999年,随着网页加载的外部资源越来越多,HTTP/1.0的性能问题愈发突出。

  2. HTTP/1.1通过引入持久连接和管道化等技术,有效提高了数据传输效率。

  3. 同时,互联网应用开始呈现出多元化、复杂化的趋势,HTTP/1.1的出现满足了这些需求。

10.4 HTTP/2.0

(1)核心技术

  • 多路复用,一个TCP连接允许多个HTTP请求。

  • 二进制帧格式,优化数据传输。

  • 头部压缩,减少传输开销。

  • 服务器推送,提前发送资源到客户端。

(2)时代背景

  1. 2015年,随着移动互联网的兴起和云计算技术的发展,网络应用对性能的要求越来越高。

  2. HTTP/2.0通过多路复用、二进制帧格式等技术,显著提高了数据传输效率和网络性能。

  3. 同时,HTTP/2.0还支持加密传输,提高了数据传输的安全性。

10.5 HTTP/3.0

(1)核心技术

  • 使用QUIC协议替代TCP协议,基于UDP构建的多路复用传输协议。

  • 减少了TCP三次握手及TLS握手时间,提高了连接建立速度。

  • 解决了TCP中的线头阻塞问题,提高了数据传输效率。

(2)时代背景:

  1. 2022年,随着5G、物联网等技术的快速发展,网络应用对实时性、可靠性的要求越来越高。

  2. HTTP/3.0通过使用QUIC协议,提高了连接建立速度和数据传输效率,满足了这些需求。

  3. 同时,HTTP/3.0还支持加密传输,保证了数据传输的安全性。


十一、总结

到这里,HTTP协议的核心知识点就讲得差不多了。我们从URL格式、请求响应报文结构,到请求方法、状态码、Header,最后动手实现了一个简单的HTTP服务器,还梳理了HTTP从0.9到3.0的演进历程。

很多同学觉得协议枯燥,觉得"我不做网络开发学这个没用"。其实不然,不管你是做后端、前端、客户端,甚至是测试、运维,只要你做的是和Web相关的开发,你每天都在和HTTP打交道。遇到跨域问题、缓存问题、性能问题、登录状态问题,追根溯源都是HTTP协议的问题。把HTTP搞懂了,很多问题自然就迎刃而解了。

希望这篇文章能帮大家真正理解HTTP协议,而不是停留在背面试题的层面。纸上得来终觉浅,绝知此事要躬行,赶紧打开编译器,自己写一个HTTP服务器试试吧!

相关推荐
梅雅达编程笔记16 小时前
零基础学 Python 第14章 | 模块、包与第三方库
开发语言·python·django·numpy·pandas
Mr__Miss16 小时前
Java泛型完全指南:从入门到精通
java·开发语言·python
赵庆明老师17 小时前
Vben精讲:14-Vben远程加载语言包
开发语言·vben
不好听61317 小时前
前端路由完全指南(下篇):懒加载、History 栈与工程化实践
前端·react.js
一个天蝎座 白勺 程序猿17 小时前
从电网改造踩坑说起:深度拆解时序大模型TimechoAI的自主可控与安全合规底气
大数据·运维·服务器·大模型·timechoai
ShineWinsu17 小时前
对于Linux:UDPsocket编程基础的解析
linux·运维·网络协议·udp·ip·端口号·进程间通信
hehelm18 小时前
AI大模型接入SDK—通用模块设计
linux·开发语言·c++
ITxiaobing202318 小时前
IP库与AppsFlyer数据对账指南:破解国家/地区数据不一致的难题
网络·网络协议
有浔则灵18 小时前
GORM钩子函数详解
网络·安全·web安全