目录
只有认知的突破 💫才能带来真正的成长 💫编程技术的学习 💫没有捷径 💫一起加油💫

🍁感谢各位的观看 🍁欢迎大家留言 🍁咱们一起加油 🍁努力成为更好的自己🍁
HTTP协议
HTTP结构
HTTP就是一个结构体,学习HTTP协议,就是学习它每个属性的含义。HTTP协议由两部分组成,HTTP请求协议和HTTP响应协议。如下图所示。

HTTP请求

对于HTTP请求,就是讲解红色圈的内容。
请求方法
GET,POST,PUT,DELETE
-
GET:用于获取一些资源,比如:获取一个登录页面。它的参数是拼接在URL链接后面的。 -
POST:用于提交资源/创建资源,比如:上传一个文件,提交一个订单。它的参数保存在data中,相比于GET,要稍安全一些。 -
PUT:传输文件。
-
DELETE:删除一些资源。
URL

对于HTTP的端口号,是被HTTP内定的,所以请求的时候,浏览器会默认给加上端口号,不需要显示输入。
/:它是web根目录。
HTTP版本
- 现在的版本主要是1.0和1.1版本,前后端的HTTP版本,要一致,否则无法通信。
换行符
"\r\n"
请求报头
-
Host:指定请求要发送到的目标域名。 -
Connection: keep-alive:表示希望保持 TCP 连接不立即关闭,以便后续请求可以复用这个连接,提升传输效率。 -
Content-Length:表示请求体(body/data)的字节,让服务器知道需要读取多少字节的数据。 -
Origin:表明请求的来源域名,主要用于跨域请求(CORS)的验证,服务器会根据这个值判断是否允许跨域。 -
Content-Type: application/x-www-form-urlencoded,表示请求体中的数据是key=value形式的 URL 编码格式。 -
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36,显示自己的机器信息。- 这个头字段告诉服务器,发起请求的客户端是 Windows 8.1 系统上的 Chrome 61 浏览器,服务器可以据此返回适配该浏览器的内容。
-
Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
HTTP响应

HTTP版本
- 现在的版本主要是1.0和1.1版本,前后端的HTTP版本,要一致,否则无法通信。
状态码&状态码描述
常用的状态码及其状态码描述,如下表格所示。
|-----|----------------------------|---------------------------------------------------|
| 状态码 | 状态码描述 | 应用样例 |
| 200 | OK | 访问网站成功,服务器返回网页的内容 |
| 201 | Created | 发布新文章,服务器返回文章资源创建成功的信息 |
| 301 | Moved Permanently(永久搬家) | 这个网页已经永久搬家到新地址了,以后别再来老地址找它了。 |
| 302 | Found / See Other(临时跳转) | 这个网页只是临时不在这,你去新地址看看,但下次有需求还是可以先来老地址问问。 |
| 304 | Not Modified(没变化,用缓存吧) | 你之前已经来过了,这个网页从上次之后就没更新过,直接用你本地缓存的版本就行,不用重新下载。 |
| 400 | Bad Request(请求格式错了) | 你提交的内容格式不对,服务器看不懂,所以拒绝处理。 |
| 401 | Unauthorized(你还没登录 / 身份失效) | 你访问的页面需要登录,但你还没登录,或者登录状态已经过期了。 |
| 403 | 403 Forbidden(你没权限看) | 你已经登录了,但这个页面 / 资源你没有权限访问,服务器直接拒绝。 |
|-----|---------------------------------|--------------------------------|
| 404 | Not Found(找不到这个页面) | 你访问的链接不存在,可能是地址输错了,或者页面被删除了。 |
| 500 | Internal Server Error(服务器自己出问题了 | 不是你的问题,是服务器内部出错了,比如代码崩溃、数据库挂了。 |
地址重定向
HTTP状态码301(永久重定向)和302(临时重定向)都依赖Location选项。
服务器会在HTTP响应中,增加个Location选项,在该选项后面放上要重定向的URL,客户端读取到Location的时候,会自动访问这个链接,自动重定向。
cpp
HTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n //重定向地址
一个简单的HTTP服务
如下所示的简单HTTP后端服务代码。请求成功以后,会返回一个简单的登录html页面.
cpp
// 包含必要的头文件
#include <iostream> // 用于输入输出操作
#include <cstring> // 用于字符串操作
#include <unistd.h> // 用于POSIX系统调用
#include <sys/socket.h> // 用于套接字操作
#include <netinet/in.h> // 用于网络地址结构
#include <arpa/inet.h> // 用于IP地址转换
// 定义服务器端口和缓冲区大小
const int PORT = 8888; // 服务器监听端口
const int BUFFER_SIZE = 1024; // 客户端请求缓冲区大小
int main() {
// 定义服务器和客户端套接字文件描述符
int server_fd, client_fd;
// 定义服务器和客户端地址结构
struct sockaddr_in server_addr, client_addr;
// 定义客户端地址长度
socklen_t client_len = sizeof(client_addr);
// 定义缓冲区,用于存储客户端请求
char buffer[BUFFER_SIZE];
// 定义登录页面的HTML内容
const char* html_content =
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>Login Page</title>\n"
"<style>\n"
"body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; }\n"
".login-container { width: 300px; margin: 100px auto; background-color: white; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }\n"
"h2 { text-align: center; margin-bottom: 20px; }\n"
".form-group { margin-bottom: 15px; }\n"
"label { display: block; margin-bottom: 5px; }\n"
"input[type='text'], input[type='password'] { width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ddd; border-radius: 3px; }\n"
"input[type='submit'] { width: 100%; padding: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 3px; cursor: pointer; }\n"
"input[type='submit']:hover { background-color: #45a049; }\n"
"</style>\n"
"</head>\n"
"<body>\n"
"<div class='login-container'>\n"
"<h2>Login</h2>\n"
"<form action='#' method='post'>\n"
"<div class='form-group'>\n"
"<label for='username'>Username:</label>\n"
"<input type='text' id='username' name='username' required>\n"
"</div>\n"
"<div class='form-group'>\n"
"<label for='password'>Password:</label>\n"
"<input type='password' id='password' name='password' required>\n"
"</div>\n"
"<input type='submit' value='Login'>\n"
"</form>\n"
"</div>\n"
"</body>\n"
"</html>";
// 构建完整的HTTP响应
// 包含HTTP状态行、响应头和响应体
std::string http_response =
"HTTP/1.1 200 OK\r\n" // HTTP状态行,200表示成功
"Content-Type: text/html\r\n" // 响应头,指定内容类型为HTML
"Content-Length: " + std::to_string(strlen(html_content)) + "\r\n" // 响应头,指定内容长度
"Connection: close\r\n" // 响应头,指定连接关闭
"\r\n" + // 空行,分隔响应头和响应体
std::string(html_content); // 响应体,登录页面HTML内容
// 创建服务器套接字
// AF_INET: 使用IPv4协议
// SOCK_STREAM: 使用TCP协议
// 0: 使用默认协议
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
std::cerr << "Socket creation failed" << std::endl;
return 1;
}
// 设置套接字选项
// SOL_SOCKET: 套接字级别
// SO_REUSEADDR: 允许重用本地地址和端口
// opt: 1表示启用该选项
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
std::cerr << "setsockopt failed" << std::endl;
return 1;
}
// 配置服务器地址结构
server_addr.sin_family = AF_INET; // 使用IPv4协议
server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口
server_addr.sin_port = htons(PORT); // 转换端口号为网络字节序
// 绑定服务器套接字到指定地址和端口
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
std::cerr << "Bind failed" << std::endl;
return 1;
}
// 开始监听客户端连接
// 5: 最大连接队列长度
if (listen(server_fd, 5) < 0) {
std::cerr << "Listen failed" << std::endl;
return 1;
}
// 输出服务器启动信息
std::cout << "Server listening on port " << PORT << "..." << std::endl;
// 主循环,不断接受和处理客户端连接
while (true) {
// 接受客户端连接
// server_fd: 服务器套接字
// (struct sockaddr*)&client_addr: 客户端地址结构
// &client_len: 客户端地址长度
client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
std::cerr << "Accept failed" << std::endl;
continue; // 继续下一次循环,接受下一个连接
}
// 读取客户端请求
ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
if (bytes_read > 0) {
// 为缓冲区添加结束符,防止字符串溢出
buffer[bytes_read] = '\0';
// 发送HTTP响应给客户端
send(client_fd, http_response.c_str(), http_response.size(), 0);
}
// 关闭客户端连接
close(client_fd);
}
// 关闭服务器套接字(实际上不会执行到这里,因为主循环是无限的)
close(server_fd);
return 0;
}
