应用层协议 HTTP

目录

[HTTP 协议](#HTTP 协议)

[认识 URL](#认识 URL)

[urlencode 和 urldecode](#urlencode 和 urldecode)

[HTTP 协议请求与响应格式](#HTTP 协议请求与响应格式)

[HTTP 请求](#HTTP 请求)

[HTTP 响应](#HTTP 响应)

[HTTP 的方法](#HTTP 的方法)

[HTTP 常见方法](#HTTP 常见方法)

[HTTP 的状态码](#HTTP 的状态码)

[HTTP 常见 Header](#HTTP 常见 Header)


HTTP 协议

虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一。

在互联网世界中,HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。

HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协 议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息。

认识 URL

平时我们俗称的 "网址" 其实就是说的 URL

urlencode 和 urldecode

像 / ? : 等这样的字符, 已经被 url 当做特殊意义理解了. 因此这些字符不能随意出现. 比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.

转义的规则如下:

将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位做一位,前面加上%,编码成%XY 格式

例如:

"+" 被转义成了 "%2B"

urldecode 就是 urlencode 的逆过程;

HTTP 协议请求与响应格式

HTTP 请求

  • 首行: [方法] + [url] + [版本]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度;

编写 HTTP 请求的代码 - 验证 http 请求(我们后面专门出一篇来讲)

HTTP 响应

  • 首行: [版本号] + [状态码] + [状态码解释]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在 Header 中会有一个 Content-Length 属性来标识 Body 的长度; 如果服务器返回了一 个 html 页面, 那么 html 页面内容就是在 body 中.

基本的应答格式

HTTP 的方法

其中最常用的就是 GET 方法和 POST 方法.

HTTP 常见方法

  1. GET 方法(重点)

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

示例:GET /index.html HTTP/1.1

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

form 表单:https://www.runoob.com/html/html-forms.html

cpp 复制代码
要通过历史写的 http 服务器,验证 GET 方法,这里需要了解一下 FORM 表单的问题
这里就要引入 web 根目录,文件读取的基本操作了
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;
}

FORM 表单是 HTML 中专门用于收集用户输入数据并提交给服务器的核心组件,核心作用是搭建「用户输入→数据传输」的桥梁,以下是极简核心介绍:

  1. 核心功能

接收用户输入(如文本、选择、勾选等),并将输入数据按指定方式(如 GET/POST)发送到目标服务器。

  1. 关键属性(必懂)
属性 作用
action 数据提交的目标地址(如 http://localhost:8080),即服务器接收数据的 URL。
method 数据提交的 HTTP 方法(默认 GET,常用 GET/POST),决定数据如何传输。
name(表单元素) 每个输入框(input、select 等)必须带的属性,是数据的「键名」(服务器靠它识别参数)。
  1. 基础结构

html

预览

复制代码
<form action="目标URL" method="提交方法">
  <!-- 表单输入项(必须有 name 属性) -->
  用户名:<input type="text" name="username"><br>
  密码:<input type="password" name="pwd"><br>
  <!-- 提交按钮(触发数据提交) -->
  <button type="submit">提交</button>
</form>
  1. 核心注意点
  • name 属性的输入项,数据不会被提交(服务器收不到)。
  • method="get" 时,数据会拼在 URL 后(如 ?username=xxx&pwd=yyy),可见且长度有限。
  • 常用输入元素:type="text"(文本)、password(密码)、checkbox(多选)、radio(单选)、select(下拉选择)。
  1. POST 方法(重点)

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

示例:POST /submit.cgi HTTP/1.1

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

form 表单:https://www.runoob.com/html/html-forms.html

  1. PUT 方法(不常用)

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

示例:PUT /example.html HTTP/1.1

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

  1. HEAD 方法

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

示例:HEAD /index.html HTTP/1.1

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

cpp 复制代码
// 使用 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
  1. DELETE 方法(不常用)

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

示例:DELETE /example.html HTTP/1.1

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

  1. OPTIONS 方法

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

示例:OPTIONS * HTTP/1.1

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

索所以它会有两种效果:不支持的效果和支持的效果

要理解这两种 "效果",核心是看 服务器是否响应了 OPTIONS 方法的核心需求(查询资源支持的 HTTP 方法),以及返回的结果是否符合预期。下面给出的 nginx 测试输出,逐句拆解:

一、先明确 OPTIONS 方法的核心目的

OPTIONS 就像一个 "询问":"嘿,服务器,你对 http://127.0.0.1/ 这个资源,允许我用哪些 HTTP 方法(GET/POST/OPTIONS 等)访问呀?"服务器的回应,就决定了是 "支持" 还是 "不支持" 这种 "询问"。

二、"不支持的效果":服务器拒绝 OPTIONS 询问

cpp 复制代码
// 搭建一个 nginx 用来测试
// sudo apt install nginx
// sudo nginx -- 开启
// ps ajx | grep nginx -- 查看
// sudo nginx -s stop -- 停止服务
$ sudo nginx -s stop
$ ps ajx | grep nginx
2944845 2945390 2945389 2944845 pts/1 2945389 S+ 1002 0:00grep --color=auto nginx
$ sudo nginx
$ ps axj | grep nginx
1 2945393 2945393 2945393 ? -1 Ss 0 0:00nginx: master process nginx
2945393 2945394 2945393 2945393 ? -1 S 33 0:00nginx: worker process
2945393 2945395 2945393 2945393 ? -1 S 33 0:00nginx: worker process
2944845 2945397 2945396 2944845 pts/1 2945396 S+ 1002 0:00grep --color=auto nginx
// -X(大 x) 指明方法
$ curl -X OPTIONS -i http://127.0.0.1/
HTTP/1.1 405 Not Allowed
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 16 Jun 2024 08:48:22 GMT
Content-Type: text/html
Content-Length: 166
Connection: keep-alive
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>

对应给出的第一个测试结果:

http

复制代码
HTTP/1.1 405 Not Allowed  // 状态码:405 不允许
// 其他响应头...
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<!-- 错误页面内容 -->
</body>
</html>

含义:

服务器 拒绝处理你发起的 OPTIONS 询问,具体表现为:

  1. 状态码返回 405 Not Allowed:明确告诉客户端 "你用 OPTIONS 方法访问这个资源,是不被允许的";
  2. 没有返回 Allow 响应头(核心查询结果):因为服务器拒绝了询问,所以不会告诉你它支持哪些方法;
  3. 响应体是 nginx 的默认错误页面:只是给用户展示 "出错了",没有任何有用的查询信息。

简单说:服务器 "不想回答" 你的 OPTIONS 询问,直接拒绝了。

三、"支持的效果":服务器正常回应 OPTIONS 询问

cpp 复制代码
C++
HTTP/1.1 200 OK
Allow: GET, HEAD, POST, OPTIONS
Content-Type: text/plain
Content-Length: 0
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 16 Jun 2024 09:04:44 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization// 注意:这里没有响应体,因为 Content-Length 为 0

对应给出的第二个测试结果:

http

复制代码
HTTP/1.1 200 OK  // 状态码:200 成功
Allow: GET, HEAD, POST, OPTIONS  // 核心:返回支持的方法列表
Content-Type: text/plain
Content-Length: 0  // 响应体长度为 0(无内容)
// CORS 相关头(跨域场景用):
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization

含义:

服务器 接受并正确响应了 OPTIONS 询问,具体表现为:

  1. 状态码返回 200 OK:明确告诉客户端 "你的询问我收到了,处理成功";
  2. 核心响应头 Allow:直接返回查询结果 ------ 该资源支持的 HTTP 方法(GET/HEAD/POST/OPTIONS),这正是 OPTIONS 方法要的核心信息;
  3. 响应体为空(Content-Length: 0):因为 "支持的方法列表" 已经通过 Allow 头传递了,不需要额外的页面内容;
  4. 额外的 Access-Control-* 头(可选):如果是跨域场景(比如前端从 A 域名访问 B 域名的资源),服务器会额外返回这些头,告诉浏览器 "跨域访问时允许的方法 / 请求头",这是对 OPTIONS 询问的补充响应(常见于前后端分离项目)。

简单说:服务器 "认真回答" 了你的 OPTIONS 询问,把你想知道的 "支持哪些方法" 明确告诉你了。

四、关键区别总结

特征 不支持的效果 支持的效果
状态码 405 Not Allowed(错误) 200 OK(成功)
核心 Allow 无(没返回支持的方法) 有(明确列出支持的方法)
响应体 错误页面(HTML 内容) 空(不需要额外内容)
本质 服务器拒绝 OPTIONS 询问 服务器接受并响应 OPTIONS 询问

补充:为什么会有两种效果?

这是 nginx 的 配置差异 导致的:

  • 第一个测试(405):默认 nginx 可能未开启对 OPTIONS 方法的支持,或者目标资源的配置中禁止了 OPTIONS 方法;
  • 第二个测试(200):手动配置了 nginx,允许 OPTIONS 方法,并指定了 Allow 头和 CORS 相关头(比如前后端分离项目中,需要配置这些来支持跨域预检请求)。

如果后续需要让 nginx 支持 OPTIONS 方法,核心就是在配置文件中添加对 OPTIONS 的允许,并指定 Allow 头即可。

HTTP 的状态码

最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway)

以下是较为详细的状态码表格,大家可以进行参考

以下是仅包含重定向相关状态码的表格:

关于重定向的验证,以 301 为代表

**HTTP 状态码 301(永久重定向)和 302(临时重定向)都依赖 Location 选项。**以下是关于两者依赖 Location 选项的详细说明:

HTTP 状态码 301(永久重定向):

  • 当服务器返回 HTTP 301 状态码时,表示请求的资源已经被永久移动到新的位 置。
  • 在这种情况下,服务器会在响应中添加一个 Location 头部,用于指定资源的新位置。这个 Location 头部包含了新的 URL 地址,浏览器会自动重定向到该地址。
  • 例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:
cpp 复制代码
C++
HTTP/1.1 301 Moved Permanently\r\n
Location: https://www.new-url.com\r\n

HTTP 状态码 302(临时重定向):

  • 当服务器返回 HTTP 302 状态码时,表示请求的资源临时被移动到新的位置。
  • 同样地,服务器也会在响应中添加一个 Location 头部来指定资源的新位置。浏览器会暂时使用新的 URL 进行后续的请求,但不会缓存这个重定向。
  • 例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:
cpp 复制代码
C++
HTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n

总结:无论是 HTTP 301 还是 HTTP 302 重定向,都需要依赖 Location 选项来指定资源的新位置。这个 Location 选项是一个标准的 HTTP 响应头部,用于告诉浏览器应该将请求重定向到哪个新的 URL 地址。

HTTP 常见 Header

  • Content-Type: 数据类型(text/html 等)
  • Content-Length: Body 的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上;
  • User-Agent: 声明用户的操作系统和浏览器版本信息;
  • referer: 当前页面是从哪个页面跳转过来的;
  • Location: 搭配 3xx 状态码使用, 告诉客户端接下来要去哪里访问;
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;

关于 connection 报头

HTTP 中的 Connection 字段是 HTTP 报文头的一部分,它主要用于控制和管理客户端与服务器之间的连接状态

核心作用

  • 管理持久连接:Connection 字段还用于管理持久连接(也称为长连接)。持久连接允许客户端和服务器在请求/响应完成后不立即关闭 TCP 连接,以便在同一个连接上发送多个请求和接收多个响应。

持久连接(长连接)

  • HTTP/1.1:在 HTTP/1.1 协议中,默认使用持久连接。当客户端和服务器都不明 、确指定关闭连接时,连接将保持打开状态,以便后续的请求和响应可以复用同一个连接。
  • HTTP/1.0:在 HTTP/1.0 协议中,默认连接是非持久的。如果希望在 HTTP/1.0 上实现持久连接,需要在请求头中显式设置 Connection: keep-alive。

语法格式

  • Connection: keep-alive:表示希望保持连接以复用 TCP 连接。
  • Connection: close:表示请求/响应完成后,应该关闭 TCP 连接。

下面附上一张关于 HTTP 常见 header 的表格

相关推荐
HIT_Weston1 小时前
45、【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 分析(二)
前端·http·gitlab
拾忆,想起1 小时前
Dubbo服务超时与重试策略配置指南:构建 resilient 微服务架构
服务器·网络·微服务·云原生·架构·dubbo
yuanjj882 小时前
域格移芯平台模块FTP下载应用
单片机·物联网·网络协议
MarkHD2 小时前
车辆TBOX科普 第28次 AT命令集与移动通信技术入门:从基础到4G/5G网络详解
网络·5g
霍格沃兹测试开发学社-小明2 小时前
测试左移2.0:在开发周期前端筑起质量防线
前端·javascript·网络·人工智能·测试工具·easyui
wuli_滔滔2 小时前
【贡献经历】从零开始为Kurator编写一个集成测试用例:深度解析测试框架与实战指南
网络·测试用例·kurator·核心组件·设计理念
秋邱2 小时前
高等教育 AI 智能体的 “导学诊践” 闭环
开发语言·网络·数据库·人工智能·python·docker
F36_9_2 小时前
在线协作工具十款测评
网络·数据库
组合缺一2 小时前
Solon AI 开发学习6 - chat - 两种 http 流式输入输出
python·学习·http