本篇博客,我们将共同探索HTTP协议的工作原理,理解它是如何在客户端和服务器之间传递信息的。我们将深入研究HTTP请求和响应的结构,了解状态码、头部信息和常见的HTTP方法。同时,我们还会讨论HTTPS的安全机制,了解如何保护数据的传输安全。
目录
一、浏览器与服务器通信过程(面试)
HTTP 协议(超文本传输协议,不仅可以传输文本文件 还可以传视频,图片,声音 )是一种应用层协议,主要用于浏览器与 web 服务器通信使用,而 HTTP 协议在传输层使用的还是 TCP 协议。浏览器需要和 web 服务器三次握手建立连接后,才可以发送 HTTP 请求报文,服务器收到请求报文后,向浏览器回复 HTTP 应答报文。浏览器向服务器发起连接前,需要得到服务器的 IP 及端口。用户在浏览器中通常只输入网址(网站域名),浏览器会通过 DNS 服务查询获取到服务器的 IP 地址。对于端口来讲, 使用 HTTP 协议的程序一般默认使用 80 端口。整个过程如下图所示:
长连接:
浏览器服务器建立连接后,如果两次以上的请求复用同一个 TCP 连接,则称之为长连接。
短连接:
如果浏览器发送一次请求报文,服务器回复一次应答就断开连接,下次交互再重新进行三次握手建立连接,那么就被称作短连接。使用长连接显然是更好一些,可以减少网络中的 同步报文,也使得服务器的响应速度变快。
注意:
1024以内的端口只有管理员才能使用,因此,必须切换到管理员身份。
常见的 web 服务器有:
◼ Apache: 简单、速度快、性能稳定,并可做代理服务器使用
◼ IIS(Internet Information Server):安全性、强大、灵活
◼ Nginx:小巧而高效,可以做高效的负载均衡反向代理
◼ Tomcat:技术先进、性能稳定、免费
二、HTTP 请求报头
2.1 HTTP 的请求报头结构
HTTP 请求报头(HTTP Request Headers)是 HTTP 请求消息的一部分,包含关于客户端、请求资源以及请求本身的附加信息。请求报头帮助服务器了解请求的性质和客户端的能力,从而做出适当的响应
HTTP 请求报文段示例:
- Request Line (请求行): 包含HTTP方法(如GET、POST)、请求的资源路径、HTTP版本。
- Host: 指定请求的目标主机和端口(IP地址或者网站)。
- User-Agent: 指定发出请求的客户端软件信息。
- Accept: 指定客户端可处理的内容类型。
- Accept-Language: 指定客户端希望的语言。
- Accept-Encoding: 指定客户端支持的内容编码类型(压缩方法)。
- Connection: 指定是否需要保持连接。
2.2 HTTP 的请求方法
HTTP 请求方法(HTTP Request Methods)是客户端用来向服务器指明所要执行的操作的。
三、HTTP 应答报头
3.1 HTTP 的应答报头结构
HTTP 应答报头(HTTP Response Headers)是服务器在响应HTTP请求时返回的一组键值对,提供有关响应和服务器的更多信息。
- Status Line (状态行): 包含HTTP版本、状态码和状态描述。
- Server: 指定处理请求的服务器软件信息。
- Content-Type: 指定响应体的MIME类型。
- Content-Length: 指定响应体的字节长度。
3.2 HTTP 的应答状态
HTTP 响应状态码(HTTP Response Status Codes)是服务器在响应HTTP请求时返回的,用于指示请求的处理结果。
面试题:
- 一百开头是 信息
- 二百开头是 成功 200 OK
- 三百开头是 重定向
- 四百开头是 客户端错误 404 Not Found资源没找到 403 Forbidden
- 五百开头是 服务器错误
客户端的错误是:客户的请求错误,服务器无法响应。服务器的错误是:客户的请求没错误,服务器因为自身原因,现在没法提供服务。
四、Web 服务器的 C 语言实现(了解)
Web 服务器对应的文件是 MyHttp.c,代码示例如下, 其中使用到的页面文件(.html)需要 用户自己提供,并且和程序在同一个位置:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <fcntl.h> #include <sys/stat.h> #define DATALENGTH 1024 // 缓冲区大小 #define PATHLENGTH 128 // 文件路径长度 // 发送 HTTP 应答报头 void SendHeadData(int c, int size, int flag) { char buff[DATALENGTH] = "HTTP/1.0 "; // HTTP 响应协议版本 if (flag) { strcat(buff, "200 OK\r\n"); // 成功响应状态码 } else { strcat(buff, "404 Not Found\r\n"); // 文件未找到状态码 } strcat(buff, "Server: MyWeb/1.0\r\n"); // 服务器信息 strcat(buff, "Content-Length: "); sprintf(buff + strlen(buff), "%d", size); // 响应内容长度 strcat(buff, "\r\n"); strcat(buff, "Content-Type: text/html;charset=utf-8\r\n"); // 响应内容类型 strcat(buff, "\r\n"); send(c, buff, strlen(buff), 0); // 发送响应头 } // 发送页面文件的内容 void SendFileData(int c, int fd) { while (1) { char buff[DATALENGTH] = { 0 }; ssize_t n = read(fd, buff, DATALENGTH - 1); // 读取文件内容 if (n <= 0) { break; } send(c, buff, (size_t)n, 0); // 发送文件内容 } } // 处理客户端的请求数据 void DealClientData(int c) { char requestBuff[DATALENGTH] = { 0 }; int n = recv(c, requestBuff, DATALENGTH - 1, 0); // 接收客户端请求 if (n <= 0) { return; } char *file = strtok(requestBuff, " "); file = strtok(NULL, " "); int flag = 1; char path[PATHLENGTH] = "."; // 程序所在位置 strcat(path, file); // 构建文件路径 int fd = open(path, O_RDONLY); // 打开文件 if (fd == -1) { fd = open("./404.html", O_RDONLY); // 若文件未找到,则打开 404 页面 flag = 0; } struct stat st; fstat(fd, &st); // 获取文件信息 SendHeadData(c, st.st_size, flag); // 发送响应头 SendFileData(c, fd); // 发送文件内容 close(fd); // 关闭文件描述符 } // 初始化服务器的套接字 int InitSocket() { int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字 if(sockfd == -1) return -1; struct sockaddr_in saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = htons(80); // 端口号设为 80 saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // IP 地址设为本地回环地址 int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)); // 绑定地址 if(res == -1) return -1; res = listen(sockfd, 5); // 开始监听连接请求 if(res == -1) return -1; return sockfd; } int main() { int sockfd = InitSocket(); assert(sockfd != -1); while (1) { struct sockaddr_in caddr; socklen_t len = sizeof(caddr); int c = accept(sockfd, (struct sockaddr*)&caddr, &len); // 接受客户端连接 if (c < 0) { continue; } DealClientData(c); // 处理客户端请求 close(c); // 关闭连接 } exit(0); }
上述代码实现了一个简单的Web服务器。它能够接收客户端的HTTP请求,并根据请求内容返回相应的文件内容或错误页面。服务器通过套接字监听端口80,接受客户端连接请求。当接收到请求后,根据请求内容打开对应的文件,并将文件内容作为HTTP响应返回给客户端。如果请求的文件不存在,则返回404页面。
至此,已经讲解完毕!篇幅较长,慢慢消化,以上就是全部内容!请务必掌握,创作不易,欢迎大家点赞加关注评论,您的支持是我前进最大的动力!下期再见!