【Linux】一文读懂HTTP协议:从原理到应用

news/2024/4/27 9:32:28/文章来源:https://blog.csdn.net/m0_63639164/article/details/130094113

​🌠 作者:@阿亮joy.
🎆专栏:《学会Linux》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
在这里插入图片描述

目录

    • 👉HTTP协议👈
      • 什么是HTTP协议
      • 认识URL
      • HTTP协议格式
      • HTTP Demo
      • HTTP的方法
      • HTTP的状态码
      • HTTP常见的报头
      • HTTP的主要特征
    • 👉抓包工具👈
      • 常见的抓包工具
      • 抓包工具的原理
    • 👉总结👈

👉HTTP协议👈

在网络版计算器一文中,我们通过手动地定制协议来加深对协议的认识。虽然我说应用层协议是由程序猿自己定,但实际上已经有大佬们定义了一些现成的、又非常好用的应用层协议,供我们直接参考使用,其中 HTTP 协议就是其中之一。

什么是HTTP协议

HTTP(超文本传输协议)是一种应用层协议,用于在客户端和服务器之间传输超文本。它是 Web 的基础,可用于检索和提交信息,例如 HTML 文件、图像、样式表等。HTTP 是无状态的,也就是说每个请求都是独立的,服务器不会存储任何有关先前请求的信息。HTTP 协议常用于浏览器与 Web 服务器之间的通信。

认识URL

平时我们俗称的网址,其实就是说的 URL。URL,全称是Uniform Resource Locator,即统一资源定位符,它是互联网上用来定位资源的标准方式。URL 是由多个部分组成,通常包含以下信息:

  • 协议:例如 http、https、ftp、file 等。
  • 域名:指向某个 IP 地址的可读性更好的别名,例如 www.example.com。
  • 端口:应用程序使用的端口号。我们所请求的网络服务对应的端口号都是众所周知的,如 HTTP 服务的默认端口号是80,而 HTTPS 服务的默认端口号是443。
  • 路径:资源在服务器上的路径。
  • 参数:向脚本传递参数。
  • 锚点:页面内部的位置。

URL 通常被用于定位 Web 页面、图像、视频、音频、文件等网络资源。它是一种标准化的格式,可以在浏览器中输入 URL,以访问特定的网络资源。

我们平时上网的目的无非两种:一、我们想要获取资源,二、我们想要上传资源。假设我们现在想要获取资源,在我们没有获取到资源之前,这个资源在服务器上。而一个服务器上可能存在多种资源(本质就是文件),那服务器是如何找到我们需要的资源,并将该资源通过网络交给我们呢?

其实我们在向服务器请求资源时,就会在 URL 内部带上资源所在的路径,这样服务器就可以通过该路径找到我们所需要的资源并交给我们。

在这里插入图片描述

urlencode 和 urldecode

在 URL 中,某些字符具有特殊含义。这些字符包括保留字符(如 /、?、& 等)和非 ASCII 字符(如中文、日文等)。因此,如果要在 URL 中包含这些字符,需要将它们进行编码。URL 编码是一种将 URL 中的特殊字符转换为标准 ASCII 字符的方法。

urlencode 是 URL 编码的过程,它将 URL 中的非 ASCII 字符和保留字符进行编码,以便在 URL 中安全地传输。具体来说,urlencode 会将非 ASCII 字符转换成它们的 UTF-8 编码,然后将每个字节转换成 %XX 的形式,其中 XX 是两个十六进制数字表示的字节值。转换的规则:将需要转码的字符转为十六进制,然后从右到左,取4位(不足4位直接处理),每两位做一位,前面加上 %,编码成 %XX。

例如,“hello, 世界” 在进行 urlencode 之后会被转换为 “hello%2C%20%E4%B8%96%E7%95%8C”。

urldecode 是将 URL 编码的字符串还原为原始字符串的过程。它将 %XX 形式的编码转换为相应的字节,并将 UTF-8 编码的字节序列还原为原始的 Unicode 字符。

在这里插入图片描述

HTTP协议格式

在 HTTP 协议中,客户端向服务器发送请求,服务器接收并响应请求。请求和响应都有特定的格式。

在这里插入图片描述
HTTP请求报文格式

请求通常由请求行、请求报头、空行和请求正文四部分组成。请求行包括请求方法、请求 URL 和 HTTP 协议版本;请求报头是一组键值对,用来描述客户端发送的请求的一些信息,例如请求的 Host、User-Agent 等。;请求正文是可选的,可以没有,通常只有在请求方法为 POST 或 PUT 时才会有请求体,用于传输客户端提交的数据。

在这里插入图片描述

注:请求中的 HTTP 协议版本是客户端告知服务端,客户端所采用的的 HTTP 协议版本。

HTTP相应报文格式

响应报文也由三部分组成:状态行、响应报头、空行和响应正文。状态行包括 HTTP 协议版本、状态码和状态码描述。响应报头和请求报头类似,也是一组键值对,用于描述服务器发送的响应的一些信息,例如响应的 Content-Type、Content-Length 等。响应正文用于传输服务器返回的数据。

在这里插入图片描述
注:响应中的 HTTP 协议版本是服务端告知客户端,服务端所采用的 HTTP 协议版本。

我们知道,每一层协议都需要考虑封装和解包的问题,也就是如何区分报头和有效载荷(正文)的问题?那 HTTP 是如何区分报头和有效载荷的呢?很明显,HTTP 是通过 \r\n(区分一行的内容) 和空行来区分报头和有效载荷的。

现在可以将报头和有效载荷区分开来了,那如何得知有效载荷的大小呢?如果有效载荷存在,那么报头中会有一个 Content-Length 属性来标识有效载荷的大小。

HTTP Demo

Log.hpp

#pragma once#include <cstdio>
#include <cstdarg>
#include <string>
#include <iostream>
#include <ctime>// 日志等级
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4#define LOGFILE "./Calculate.log"const char* levelMap[] = 
{"DEBUG","NORMAL","WARNING","ERROR","FATAL"
};void logMessage(int level, const char* format, ...)
{// 只有定义了DEBUG_SHOW,才会打印debug信息// 利用命令行来定义即可,如-D DEBUG_SHOW
#ifndef DEBUG_SHOWif(level == DEBUG) return;
#endifchar stdBuffer[1024];   // 标准部分time_t timestamp = time(nullptr);// struct tm *localtime = localtime(&timestamp);snprintf(stdBuffer, sizeof stdBuffer, "[%s] [%ld] ", levelMap[level], timestamp);char logBuffer[1024];   // 自定义部分va_list args;   // va_list就是char*的别名va_start(args, format); // va_start是宏函数,让args指向参数列表的第一个位置// vprintf(format, args); // 以format形式向显示器上打印参数列表vsnprintf(logBuffer, sizeof logBuffer, format, args);va_end(args);   // va_end将args弄成nullptrFILE *fp = fopen(LOGFILE, "a");// printf("%s%s\n", stdBuffer, logBuffer);fprintf(fp, "%s%s\n", stdBuffer, logBuffer);fclose(fp);
}

Sock.hpp

#pragma once#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>
#include <cstring>
#include "Log.hpp"class Sock
{
private:const static int backlog = 20;public:Sock() {}// 返回值是创建的套接字int Socket(){int sock = socket(AF_INET, SOCK_STREAM, 0);if (sock < 0){logMessage(FATAL, "Create Socket Error! Errno:%d Strerror:%s", errno, strerror(errno));exit(2);}logMessage(NORMAL, "Create Socket Success! Socket:%d", sock);return sock;}// 绑定端口号void Bind(int sock, uint16_t port, std::string ip = "0.0.0.0"){struct sockaddr_in local;memset(&local, 0, sizeof local);local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = inet_addr(ip.c_str());if (bind(sock, (struct sockaddr *)&local, sizeof local) < 0){logMessage(FATAL, "Bind Error! Errno:%d Strerror:%s", errno, strerror(errno));exit(3);}}// 将套接字设置为监听套接字void Listen(int listenSock){if (listen(listenSock, backlog) < 0){logMessage(FATAL, "Listen Error! Errno:%d Strerror:%s", errno, strerror(errno));exit(4);}logMessage(NORMAL, "Init Server Success!");}// 接收链接,返回值是为该连接服务的套接字// ip和port是输出型参数,返回客户端的ip和portint Accept(int listenSock, std::string *ip, uint16_t *port){struct sockaddr_in src;socklen_t len = sizeof(src);int serviceSock = accept(listenSock, (struct sockaddr *)&src, &len);if (serviceSock < 0){logMessage(FATAL, "Accept Error! Errno:%d Strerror:%s", errno, strerror(errno));return -1;}if (ip)*ip = inet_ntoa(src.sin_addr);if (port)*port = ntohs(src.sin_port);return serviceSock;}// 发起连接bool Connet(int sock, const std::string &serverIP, const int16_t &serverPort){struct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_port = htons(serverPort);inet_pton(AF_INET, serverIP.c_str(), &server.sin_addr);if (connect(sock, (struct sockaddr *)&server, sizeof server) == 0)return true;elsereturn false;}~Sock() {}
};

HttpServer.hpp

#pragma once#include <iostream>
#include <functional>
#include <unistd.h>
#include <signal.h>
#include "Sock.hpp"using func_t = std::function<void(int)>;class HttpServer
{
public:HttpServer(const uint16_t& port, func_t func): _port(port), _func(func){_listenSock = _sock.Socket();_sock.Bind(_listenSock, _port);_sock.Listen(_listenSock);}~HttpServer(){if(_listenSock >= 0)close(_listenSock);}void Start(){signal(SIGCHLD, SIG_IGN);while(true){std::string clientIP;uint16_t clientPort;int sockfd = _sock.Accept(_listenSock, &clientIP, &clientPort);if(sockfd < 0) continue;// 创建子进程去处理请求if(fork() == 0){close(_listenSock);_func(sockfd);close(sockfd);exit(0);}}}private:int _listenSock;uint16_t _port;Sock _sock;func_t _func; // 回调函数
};

HttpServer.cc

#include <iostream>
#include <memory>
#include "HttpServer.hpp"void Usage(const std::string proc)
{std::cout << "\nUsage" << proc << " Port" << std::endl;
}void HandlerHttpRequest(int sock)
{// 1、读取请求char buffer[10240];ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);// 将接收到的数据直接当成字符串进行打印if(s > 0){buffer[s] = '\0';std::cout << buffer << "-----------------------" << std::endl;}// 2、构建一个HTTP响应std::string HttpResponse = "HTTP/1.1 200 OK\r\n";HttpResponse += "\r\n";HttpResponse += "<html><h3>Singing, dancing, Rap and playing basketball are my favorites</h3></html>";send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}int main(int argc, char* argv[])
{if(argc != 2){Usage(argv[0]);exit(1);}std::unique_ptr<HttpServer> ptr(new HttpServer(atoi(argv[1]), HandlerHttpRequest));ptr->Start();return 0;
}

在这里插入图片描述

注:Web 根目录并不是 Linux 系统中的根目录!!!

在这里插入图片描述

使用 telnet 工具来访问

在这里插入图片描述

代码细化

Util.hpp

#pragma once#include <iostream>
#include <vector>class Util
{
public:static void cutString(std::string s, const std::string &sep, std::vector<std::string> *out){std::size_t start = 0;while (start < s.size()){auto pos = s.find(sep, start);if (pos == std::string::npos) break;std::string sub = s.substr(start, pos - start);out->push_back(sub);start += sub.size();start += sep.size();}if(start < s.size()) out->push_back(s.substr(start));}
};

cutString 接口的作用是以 sep 为分割符,将传入的字符串 s 进行切分,并尾插到输出型参数 out 中。

#define ROOT "./wwwroot" // Web更目录
#define HOMEPAGE "/index.html" // 如果没有指定请求的资源,服务端默认给客户端返回该资源void HandlerHttpRequest(int sock)
{// 1、读取请求char buffer[10240];ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);// 将接收到的数据直接当成字符串进行打印if(s > 0){buffer[s] = '\0';std::cout << buffer << "-----------------------" << std::endl;}// 2、构建一个HTTP响应std::vector<std::string> vline; Util::cutString(buffer, "\r\n", &vline); std::vector<std::string> vblock;Util::cutString(vline[0], " ", &vblock); // 提取HTTP请求// 请求资源的路径std::string file = vblock[1]; // vblock[1]是要请求资源的路径std::string target = ROOT; // target为请求资源的路径if(file == "/") file = HOMEPAGE; // 如果请求资源的路径是Web根目录,那么给客户端返回默认的资源target += file;std::cout << target << std::endl;std::string content;std::ifstream in(target);if(in.is_open()){std::string line;while(std::getline(in, line)){content += line; // 将文件中的全部内容读取出来}in.close();}std::string HttpResponse;// content为空,说明请求的资源不存在if(content.empty()) HttpResponse = "HTTP/1.1 404 NotFound\r\n";else HttpResponse = "HTTP/1.1 200 OK\r\n";HttpResponse += "\r\n";HttpResponse += content;send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}

在这里插入图片描述
./wwwroot/a/b/index.html

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Summer Beach</title><style>/* 设置背景图片和背景颜色 */body {background-image: url("https://images.unsplash.com/photo-1627259317488-8ecb5120a71a?ixid=MnwxMjA3fDB8MHxwcm9maWxlLXBhZ2V8NjJ8MzQ1fHxlbnwwfHx8fDE2MTk5MjIzNzA&ixlib=rb-1.2.1");background-color: #a9d9e7;background-size: cover;background-position: center;margin: 0;padding: 0;font-family: Arial, sans-serif;}/* 设置标题的样式 */h1 {text-align: center;margin-top: 50px;font-size: 64px;color: #fff;text-shadow: 2px 2px #000;}/* 设置主要内容区域的样式 */#main {width: 80%;margin: 50px auto;background-color: rgba(255, 255, 255, 0.8);padding: 20px;box-shadow: 0px 0px 20px #000;}/* 设置表格的样式 */table {margin-top: 20px;width: 100%;border-collapse: collapse;text-align: center;}/* 设置表格的表头样式 */th {background-color: #222;color: #fff;font-weight: bold;padding: 10px;}/* 设置表格的单元格样式 */td {padding: 10px;}/* 设置按钮的样式 */button {display: block;margin: 30px auto;padding: 10px;border-radius: 5px;border: none;background-color: #222;color: #fff;font-size: 24px;cursor: pointer;transition: all 0.3s ease-in-out;}/* 设置按钮的鼠标悬停样式 */button:hover {background-color: #333;}</style></head><body><h1>Summer Beach</h1><div id="main"><h2>Travel Destinations</h2><table><tr><th>Location</th><th>Description</th><th>Photo</th></tr><tr><td>Maldives</td><td>A tropical paradise with crystal clear waters and white sandy beaches.</td><td><img src="https://images.unsplash.com/photo-1526672312463-7d28e8f0d227?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8bWFsZGl2ZXN8ZW58MHx8MHx8&ixlib=rb-1.2.1&

./wwwroot/index.html

<!DOCTYPE html>
<html>
<head><title>远方的诗和画</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>/* 样式表 */body {background-color: #f8f8f8;font-family: Arial, sans-serif;font-size: 16px;line-height: 1.5;margin: 0;padding: 0;}header {background-color: #333;color: #fff;padding: 20px;text-align: center;}h1 {margin: 0;}main {max-width: 800px;margin: 20px auto;padding: 0 20px;}img {max-width: 100%;height: auto;margin: 20px 0;}blockquote {font-style: italic;margin: 20px 0;padding-left: 20px;border-left: 2px solid #333;}</style>
</head>
<body><header><h1>远方的诗和画</h1><p>走过千山万水,追寻梦中的旅途</p></header><main><h2>关于旅游的诗句</h2><blockquote><p>夜泊牛渚怀古怨,<br>不堪看点滴,<br>尽向湖心画短鸟。</p><footer>——宋·杨万里《夜泊牛渚怀古怨》</footer></blockquote><blockquote><p>远山霭漫,<br>长河落日圆;<br>这一生,<br>与谁度过。</p><footer>——唐·岑参《旅怀》</footer></blockquote><h2>风景如画的地方</h2><p>以下是一些值得一去的风景胜地:</p><ul><li>黄山</li><li>张家界</li><li>九寨沟</li><li>桂林漓江</li><li>西湖</li></ul><h2>一些美丽的图片</h2><p>以下是一些关于旅游的美丽图片:</p><img src="https://picsum.photos/id/1015/800/400" alt="图片1"><img src="https://picsum.photos/id/1024/800/400" alt="图片2"><img src="https://picsum.photos/id/1035/800/400"

在这里插入图片描述
在这里插入图片描述

HTTP的方法

在这里插入图片描述

我们平时的上网行为其实就两:1. 从服务器端拿取资源(GET) 2. 把客户端的数据提交到服务端中(POST、GET)。

在这里插入图片描述

GET 是获取资源的方法,而图片和音频都是网络资源,因此使用 GET 方法可以方便地获取这些资源。此外,GET方法是幂等的,即对同一资源的多次请求返回的结果是相同的,适合用于获取静态资源。

GET 和 POST 的区别

想要知道 GET 和 POST的区别就需要了解表单。

表单(Form)是 HTML 中一种常用的元素,它是用来接受用户输入的一种方式。表单包含了各种表单元素,如文本框、单选框、复选框、下拉框等,用户可以通过这些元素输入信息,然后通过表单提交(Submit)按钮将这些信息发送到后端服务器。

表单的基本语法如下:

<form action="提交地址" method="提交方式">表单元素<input type="submit" value="提交">
</form>

其中,action 属性指定了表单提交的地址,method 属性指定了表单提交的方式。常见的提交方式有两种:GET 和 POST。

在这里插入图片描述
表单提交后,后端服务器会接收到表单数据,可以通过对应的程序对表单数据进行处理,并给出响应。注:表单中的数据会变成 HTTP 请求中的一部分!!!

表单示例代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>阿亮Joy.</title>
</head><body><h3>须知少年凌云志,曾许人间第一流</h3><form name="input" action="/a/b/index.html" method="GET">Username: <input type="text" name="user"> <br/>Password: <input type="password" name="pwd"> <br/><input type="submit" value="Submit"></form>
</body></html>

GET 方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

表单提交方式为 GET 最大的特点就是通过 URL 来传递参数,会将用户名和密码等私密信息回显到 URL中,称为 URL 的一部分。因为用户名和密码成为 URL 中的参数,而我们并没有对该参数进行处理,所以就出现该网页无法正常运作的提示。

POST 方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

POST 方法是通过 HTTP 请求的正文来提交参数,不会将用户名和密码等私密信息回显到 URL 中,私密性有所保证。因为用户名和密码等私密信息等没有回显到 URL 中,所以我们就可以访问到 /a/b/index.html 存在的网页了。

需要注意的是:私密性有所保证并不意味着安全。因为表单在提交的过程中,数据是明文传输的。如果想要保证安全,就需要通过加密和解密来解决,而加密传输可以采用 HTTPS 等安全协议。

GET 和 POST 方法的区别总结如下:

  • 参数传递方式不同:GET 请求是通过 URL 的查询字符串传递参数,而 POST 请求则是通过请求正文传递参数。

  • 参数传递大小限制不同:由于 GET 请求是通过 URL 传递参数,因此它的参数传递大小受到浏览器和服务器对 URL 长度的限制,通常不能超过 2KB;而 POST 请求的参数传递大小没有限制,但是服务器可以设置最大接收参数大小。

  • 缓存处理方式不同:GET 请求可以被浏览器缓存,而 POST 请求则不会被浏览器缓存。

  • 安全性不同:由于 GET 请求参数会暴露在 URL 中,因此它不太安全,而 POST 请求的参数则不会暴露在 URL 中,相对来说比较安全。

GET 和 POST 方法的主要应用场景

  • GET 方法会将请求参数添加在 URL 中,形成一个完整的 URL,然后发送给服务器。它的主要应用场景是请求资源,例如浏览网页、查看图片等。
  • POST 方法会将请求参数封装在 HTTP 请求正文中,然后发送给服务器。它的主要应用场景是提交表单数据,例如登录、注册等。

HEAD 方法

在这里插入图片描述

HEAD 方法请求获取指定资源的头部信息,与 GET 方法类似,但不返回响应的正文部分。

OPTIONS 方法

在这里插入图片描述
OPTIONS 方法请求获取指定资源支持的通信选项,可以用来查询服务器支持哪些方法或者哪些头部。

注:除了 GET 和 POST 方法外,很多方法很大程度都是不支持的或者支持的不是很好,我们只需要知道即可。

HTTP的状态码

在这里插入图片描述
HTTP 状态码是 Web 服务器返回给客户端的 3 位数字代码,用于表示当前 HTTP 请求的处理状态。以下是常见的 HTTP 状态码及其含义:

  • 200 OK:服务器成功处理了请求。
  • 201 Created:请求已经被实现,而且有一个新的资源已经依据请求的需要而建立。
  • 204 No Content:服务器成功处理了请求,但是没有返回任何内容。
  • 301 Moved Permanently:被请求的资源已永久移动到新位置。
  • 302 Found:请求的资源现在临时从不同的 URL 响应请求,但将来可能会恢复原始地址。
  • 304 Not Modified:请求的资源在服务器上没有被修改过,可以直接使用浏览器缓存。
  • 400 Bad Request:服务器无法理解请求的格式,客户端不应该重复提交这个请求。
  • 401 Unauthorized:请求需要认证或者认证失败。
  • 403 Forbidden:服务器理解请求,但是拒绝执行该请求。
  • 404 Not Found:服务器找不到请求的资源。
  • 500 Internal Server Error:服务器发生错误,无法完成请求。
  • 502 Bad Gateway:服务器作为网关或者代理,从上游服务器收到无效响应。
  • 503 Service Unavailable:服务器当前无法处理请求,一般用于临时维护或者过载状态。

永久重定向 301 VS 临时重定向 302、307

301 状态码表示永久重定向,意味着请求的 URL 已经被永久移动到了新的位置,以后所有对原始 URL 的请求都将自动转移到新的URL地址,浏览器也将自动更新书签和搜索引擎也将更新其索引。

HTTP/1.1 301 Moved Permanently
Location: http://www.example.com/new-location

302 状态码表示临时重定向,意味着请求的 URL 已经被暂时移动到了新的位置,浏览器会自动跳转到新的 URL 地址,但搜索引擎不会更新其索引。

HTTP/1.1 302 Found
Location: http://www.example.com/new-location

307 状态码与 302 类似,表示临时重定向,但是客户端不应该改变请求方法,而是继续使用原来的请求方法。例如,如果使用 POST 方法请求一个资源,并且服务器返回 307 状态码,那么客户端应该用 POST 方法重新发起请求,而不是使用 GET 方法。307 状态码通常用于临时重定向时需要保留原始请求方法的场景。

HTTP/1.1 307 Temporary Redirect
Location: http://www.example.com/new-location

注:永久重定向会影响用户后序的请求策略,而临时重定向不会影响用户后续的请求策略。

在这里插入图片描述

临时重定向代码演示

#define ROOT "./wwwroot"
#define HOMEPAGE "/index.html"void HandlerHttpRequest(int sock)
{// 1、读取请求char buffer[10240];ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);// 将接收到的数据直接当成字符串进行打印if(s > 0){buffer[s] = '\0';}std::cout << buffer << "-----------------------" << std::endl;// 2、构建一个HTTP响应std::vector<std::string> vline;Util::cutString(buffer, "\n", &vline);std::vector<std::string> vblock;Util::cutString(vline[0], " ", &vblock);// 请求资源的路径std::string file = vblock[1];std::string target = ROOT;if(file == "/") file = HOMEPAGE;target += file;std::cout << target << std::endl;std::string content;std::ifstream in(target);if(in.is_open()){std::string line;while(std::getline(in, line)){content += line;}in.close();}std::string HttpResponse;if(content.empty()) {HttpResponse = "HTTP/1.1 302 Found\r\n";HttpResponse += "Location: https://blog.csdn.net/m0_63639164\r\n";}else HttpResponse = "HTTP/1.1 200 OK\r\n";HttpResponse += "\r\n";HttpResponse += content;send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}

在这里插入图片描述
404 演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

HTTP常见的报头

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

Content-Length

在这里插入图片描述

在这里插入图片描述

Content-Type
在这里插入图片描述
注:HTTP 的 Content Type 也是有对照表的,需要根据资源的类型来填写。

Connection

HTTP 报头中的 Connection 是一个非常重要的字段,用于指示浏览器与服务器之间的长连接是否应该保持打开状态,以便更快地传输多个请求和响应。

  • Keep-Alive:表示浏览器与服务器之间的长连接将保持打开状态,并且后续的请求和响应可以在同一个连接上进行传输,从而减少了连接的建立和断开开销。

  • close:表示浏览器与服务器之间的连接在请求和响应完成后将立即关闭。这是 HTTP/1.0 中默认的行为。

HTTP 的长连接和短连接都是指在 TCP 层面上的连接。HTTP 协议是基于 TCP 协议的,每次 HTTP 请求和响应都需要建立和断开 TCP 连接,因此在高并发场景下会产生大量的 TCP 连接开销,从而影响性能。

短连接指每次HTTP请求和响应都建立一个新的 TCP 连接,并在请求结束后立即关闭连接。这种方式下,每次请求都需要重新建立和断开 TCP 连接,会增加连接管理的负担和开销。

在 HTTP/1.0 中,HTTP 默认采用短连接,也就是每次请求和响应都建立和断开一次 TCP 连接。在 HTTP/1.1 中,HTTP 默认采用长连接,即在一个 TCP 连接上可以连续发送多个 HTTP 请求和响应。

长连接和短连接各有优缺点,长连接可以减少 TCP 连接的建立和断开次数,降低网络开销,但长时间占用连接会增加服务器资源消耗;短连接可以保证每个请求的独立性,减少因单个请求错误导致的影响,但频繁的 TCP 连接建立和断开会影响性能。因此,根据具体的应用场景和需求选择长连接或短连接,或者结合两者的优点,使用 HTTP/2 的多路复用技术。

HTTP的主要特征

  • 无状态:每个 HTTP 请求都是独立的,服务器不会保存任何客户端的请求信息,因此 HTTP 被称为无状态协议。为了维护客户端状态,通常使用 Cookie 和 Session技术。

  • 可扩展:HTTP 报头可以通过添加自定义报头实现扩展功能。

  • 灵活:HTTP 可以传输任何类型的数据,如 HTML、图片、音频、视频等。

  • 明文传输:HTTP 是明文传输的,请求和响应中的所有内容都可以被窃听,因此使用 HTTPS 进行加密。

  • 请求 / 响应模型:HTTP 采用客户端-服务器模型,客户端发送请求,服务器发送响应。

  • 无连接:HTTP 协议不维护连接,连接是 TCP 协议维护的,HTTP直接发起请求和响应即可。

  • 缓存:HTTP 支持缓存,可以通过在响应报头中添加缓存信息控制客户端和服务器的缓存机制。

既然 HTTP 的一个主要特征是无状态,那为什么网站一般都能够记录我的状态呢?

虽然 HTTP 协议本身是无状态的,但是在实际应用中,为了实现用户的登录状态等功能,网站会在服务器端保存用户的会话状态,并分配给用户一个唯一的会话标识符(Session ID),这个会话标识符可以在每次请求时传递给服务器,服务器就可以根据这个标识符识别用户,从而实现用户状态的保持。

具体来说,当用户登录时,服务器会创建一个会话对象,保存用户的相关信息,同时生成一个唯一的 Session ID,并将其发送给客户端,通常是通过 Cookie 技术实现。之后,客户端每次请求都会携带这个 Session ID,服务器就可以根据 Session ID 查找对应的会话对象,获取用户的相关信息,从而实现用户状态的保持。

需要注意的是,由于 HTTP 协议是无状态的,因此服务器端保存的会话状态只存在于一定的时间范围内,一般会设置一个过期时间,超过过期时间后,会话状态会被清除。

在这里插入图片描述
在这里插入图片描述

Cookie 是基于 HTTP 协议实现的,可以分为文件级的 Cookie 文件和内存级的 Cookie 文件。

文件级的 Cookie 文件是存储在用户计算机上的硬盘上,是一种持久性的 Cookie。它们的过期时间可以设置为一段时间,也可以永不过期。在访问同一个网站时,浏览器会自动发送该网站存储在本地计算机上的 Cookie文件,以便在服务器端进行身份验证和授权操作。

内存级的 Cookie 文件是存储在内存中的临时 Cookie。当浏览器关闭时,它们会自动删除。内存级的 Cookie 可以用于存储一些敏感信息,如密码和银行账户信息等,以提高安全性。

注:相对来说,文件级 Cookie 文件更容易被盗取。

Cookie 和 Set-Cookie

HTTP 协议中的 Cookie 和 Set-Cookie 是 HTTP 请求和响应中的两个重要报头。其中 Cookie 是客户端请求时携带的用于身份验证和状态管理的信息,而 Set-Cookie 是服务端响应时用于设置 Cookie 的报头。

具体来说,当客户端向服务端发送 HTTP 请求时,如果之前已经设置了 Cookie,则会在请求报头中添加一个 Cookie 字段,将之前设置的 Cookie 信息携带过去,供服务端进行验证和状态管理。而当服务端向客户端发送 HTTP 响应时,如果需要设置新的 Cookie,则会在响应报头中添加一个 Set-Cookie 字段,指定新的 Cookie 信息,包括 Cookie 的名称、值、过期时间、作用域等。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

👉抓包工具👈

常见的抓包工具

抓包工具是一种网络工具,可以捕捉和分析网络通信数据包,以便进行网络故障诊断、协议分析、网络安全评估等工作。以下是几种常用的抓包工具:

  • Wireshark:Wireshark 是一款开源的网络协议分析工具,支持多种操作系统,可以用来分析和解码多种协议。Wireshark 功能强大,支持实时抓包和离线分析。

  • tcpdump:tcpdump 是一款常用的命令行抓包工具,支持多种操作系统。它可以捕获网络接口上的数据包,并将其保存到文件中,同时也可以实时分析数据包。

  • Fiddler:Fiddler 是一款基于 Windows 平台的抓包工具,主要用于 HTTP 和 HTTPS 协议的分析和调试。它可以拦截和修改客户端和服务器之间的 HTTP 流量。

  • Charles:Charles 是一款跨平台的抓包工具,支持多种操作系统。它可以拦截和分析 HTTP 和 HTTPS 流量,支持实时分析和修改。

  • Burp Suite:Burp Suite 是一款专业的网络安全测试工具,可以用来检测和利用 Web 应用程序的安全漏洞。它包含了代理服务器、扫描器、攻击工具等多种功能。

抓包工具的原理

在这里插入图片描述

抓包工具是用来捕获网络数据包的工具,其原理是通过在计算机与网络之间插入一个“中间人”来监听、记录和分析数据包的传输情况。

当我们使用抓包工具进行数据包捕获时,抓包工具会将计算机和网络之间的通信流量截获并保存在本地,然后对这些数据包进行分析和解析,以便我们可以查看和分析其中的详细信息,如协议、请求头、响应头、数据内容等。

抓包工具实现数据包捕获的主要方式有两种,一种是通过网络适配器(网卡)捕获数据包,另一种是通过端口监听捕获数据包。在捕获数据包后,抓包工具会将数据包保存在本地,并提供可视化的界面,让用户可以方便地查看和分析数据包的内容。

👉总结👈

本篇博客主要讲解了什么是HTTP协议、认识URL、HTTP协议格式、请求方法、状态码、常见报头、主要特征以及常见的抓包工具和抓包工具的原理等等。以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_103268.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器人工程师与孔乙己文学

本文内容严格按创作模板发布&#xff1a; 孔乙已是鲁迅笔下人物&#xff0c;穷困流倒还穿着象征读书人的长衫&#xff0c;迁腐、麻木。最近&#xff0c;大家自我调佩是“当代孔乙己”&#xff0c;学历成为思想负担&#xff0c;找工作时高不成低不就。你可以从以下几个角度说说…

Android---启动页+闪屏页

目录 启动页 闪屏页 启动页 app 在进入首页面的过程中&#xff0c;都会线加载一张图片然后再进入闪屏页。这样&#xff0c;可以给用户很好的体验。 作用&#xff1a;避免加载白屏页面&#xff0c;进行业务的预处理&#xff08;网络检测、数据预加载...&#xff09; 界面组成…

一款纯Web化免费SQL工具,重新定义数据库管理

SQL Studio是一款由麦聪软件研发的多数据库管理工具&#xff0c;提供Windows、Linux 和 MacOS三种版本的软件包&#xff0c;支持中英文两种语言。SQL Studio是用Java编写的&#xff0c;默认使用 JDK 8进行编译。 下载看这里: [SQLStudio] (http://www.maicongs.com/#/home/web)…

.Net Framework 4.6.1+版本的Winform程序开启Web服务,支持Http webapi

Winform程序开启Web服务 背景思路方法1方法2方法3&#xff08;本文使用的方法&#xff09; 实现在winform程序中引入几个nuget包新建一个Startup类&#xff08;叫什么名字都行&#xff09;修改Program文件创建controller 运行效果(打开浏览器&#xff0c;输入如下地址&#xff…

ThinkPHP模型操作上

ThinkPHP模型操作上 前言模型一、创建模型二、模型操作 总结 前言 在mvc架构中&#xff0c;模型的解释是写逻辑代码的地方&#xff0c;其实还可以这样理解&#xff0c;就是一串操作写在一个模型类中&#xff0c;就是你要完成某一项功能&#xff0c;将这个功能的代码写在一个mod…

记录-使用双token实现无感刷新,前后端详细代码

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 近期写的一个项目使用双token实现无感刷新。最后做了一些总结&#xff0c;本文详细介绍了实现流程&#xff0c;前后端详细代码。前端使用了Vue3Vite&#xff0c;主要是axios封装&#xff0c;服务…

(栈和队列) 232. 用栈实现队列 ——【Leetcode每日一题】

❓232. 用栈实现队列 难度&#xff1a;中等 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾int pop() 从队列…

策略模式——时势造影响

● 策略模式介绍 在软件开发中常常遇到这样的情况&#xff1a;实现某一个功能可以有多种算法或者策略&#xff0c;我们根据实际情况选择不同的算法或者策略来完成该功能。例如&#xff0c;排序算法&#xff0c;可以使用插入排序、归并排序、冒泡排序。 针对这种情况&#xff0c…

Pytorch的CNN,RNNLSTM

CNN 拿二维卷积举例&#xff0c;我们先来看参数 卷积的基本原理&#xff0c;默认你已经知道了&#xff0c;然后我们来解释pytorch的各个参数&#xff0c;以及其背后的计算过程。 首先我们先来看卷积过后图片的形状的计算&#xff1a; 参数&#xff1a; kernel_size &#xff…

Android 动画—补间动画

帧动画是通过连续播放图片来模拟动画效果&#xff0c;而补间动画开发者只需指定动画开始&#xff0c;以及动画结束"关键帧"&#xff0c;而动画变化的"中间帧"则由系统计算并补齐&#xff01; 1.补间动画的分类和Interpolator Andoird所支持的补间动画效果…

electron+vue3全家桶+vite项目搭建【14】electron多窗口,多语言切换不同步更新问题

文章目录 引入问题演示补充逻辑注意封装缓存工具类补充状态管理调整多语言初始化调整多语言切换组件 解决方案思路整理渲染进程监听语言切换主进程创建多语言切换处理语言切换组件通知主进程语言切换 最终实现效果演示 引入 我们之前在这篇文章中集成了 多语言切换&#xff0c…

【数据挖掘与商务智能决策】第十三章 数据降维之PCA 主成分分析

13.1.2 PCA主成分分析代码实现 1.二维空间降维Python代码实现 import numpy as np X np.array([[1, 1], [2, 2], [3, 3]]) Xarray([[1, 1],[2, 2],[3, 3]])# 也可以通过pandas库来构造数据&#xff0c;效果一样 import pandas as pd X pd.DataFrame([[1, 1], [2, 2], [3, 3…

数字北京城,航行在联通2000M的“大运河”

前故宫博物院院长单霁翔&#xff0c;在《大运河漂来紫禁城》一书中提到过&#xff0c;紫禁城里的石材、木材&#xff0c;甚至每一块砖&#xff0c;都是通过大运河&#xff0c;跋山涉水来到北京的。某种程度上说&#xff0c;北京城的繁荣与这条纵跨南北的“中华大动脉”密不可分…

AntdesignVue 局部全屏后Message、Select 、Modal、Date等组件不显示问题解决方案(最终版)

1、对this.$message.....这种的消息提示组件解决方案如下 在main.js中全局配置消息提示 //单独引用需修改的元素 import { message } from ant-design-vue message.config({maxCount: 1,getContainer:() > document.getElementById(showBigModal) || document.body //父组件…

Android-实现一个登录页面(kotlin)

准备工作 首先&#xff0c;确保你已经安装了 Android Studio。如果还没有安装&#xff0c;请访问 Android Studio 官网 下载并安装。 前提条件 - 安装并配置好 Android Studio Android Studio Electric Eel | 2022.1.1 Patch 2 Build #AI-221.6008.13.2211.9619390, built …

C++(继承中)

目录&#xff1a; 1.基类和派生类对象赋值转换 2.派生类当中的6个默认成员函数 --------------------------------------------------------------------------------------------------------------------------- 派生类对象可以赋值给 基类的对象/基类的指针/基类的引用&am…

Java每日一练(20230425)

目录 1. 乘积最大子数组 &#x1f31f;&#x1f31f; 2. 插入区间 &#x1f31f;&#x1f31f; 3. 删除有序数组中的重复项 II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏…

CSGO搬砖,每天1-2小时,23年最强副业非它莫属(内附操作流程)

自从我学会了CSGO搬运&#xff0c;我发现生活也有了不小的改变&#xff0c;多了一份收入&#xff0c;生活质量也就提高了一份。 其实刚接触CSGO&#xff0c;我压根就不相信这么能挣钱&#xff0c;因为在印象中&#xff0c;游戏供玩家娱乐竞技的&#xff0c;作为我这种技术渣渣…

直播系统开发中如何优化API接口的并发

概述 在直播系统中&#xff0c;API接口并发的优化是非常重要的&#xff0c;因为它可以提高系统的稳定性和性能。本文将介绍一些优化API接口并发的方法。 理解API接口并发 在直播系统中&#xff0c;API接口是用于处理客户端请求的关键组件。由于许多客户端同时连接到系统&…

HTTP1.1(十二)Cookie的格式与约束

一 Cookie的格式与约束 ① Cookies是什么 1) cookie是我们在前端编程中经常使用的概念2) 使用cookie利用浏览器帮助我们保存客户的相关状态信息,保存用户已经做了什么事情3) 重点和难点[1]、cookie的工作原理[2]、cookie的限制是什么[3]、session又是怎样与cookie关联起来 …