【计算机网络】应用层协议 -- HTTP协议
文章目录
- 1. 认识HTTP协议
- 2. 认识URL
- 3. HTTP协议格式
- 3.1 HTTP请求协议格式
- 3.2 HTTP响应协议格式
- 4. HTTP的方法
- 5. HTTP的状态码
- 6. HTTP的Header
- 7. Cookie和Session
1. 认识HTTP协议
协议。网络协议的简称,网络协议是通信计算机双方必须共同遵守的一组约定,比如怎么建立连接,怎么互相识别等。
为了使数据在网络上能够从源头到达目的,网络通信的参与方必须遵守相同的规则,我们称这套相同的规则为协议(protocol),而协议最终都需要通过计算机语言的方式表达出来。只有通信计算机双方都遵守相同的协议,计算机之间才能互相通信交流。
通俗来讲,协议就是要保证网络通信的双方、能够相互对上号。比如两个人传递纸条通过相互指定的暗号。
应用层协议
应用层协议位于网络协议栈的最顶层,负责定义应用程序之间的通信规则和数据交换方式。应用层协议允许不同设备上的不同设备上的应用程序能够相互交换数据和信息,使得互联网上的各种应用能够正常运行。
应用层协议定义了数据交换的格式、数据的编码和解码方法、通信的语义以及错误处理等规则。这些协议通常与特定的应用程序密切相关,例如Web浏览器使用HTTP协议来获取网页内容。
HTTP(Hyper Text Transfer
Protocol)又叫做超文本传输协议,是一个简单的请求-响应协议,HTTP通常运行在TCP之上。
虽然应用层协议大多是程序猿自己定的,但实际上,有大佬们定义了一些现成的、又非常好用的应用层协议,供我们直接参考使用。HTTP协议就是其中之一。
2. 认识URL
URL(Uniform Resource Lacator)叫做统一资源定位符,也就是我们通常所说的网址,是因特网的万维网服务程序上用于指定信息位置的表示方法。
一个URL大致有以下部分组成:

协议方案名
http:// 表示的是协议名称,表示请求时使用的协议,通常使用的是HTTP协议或者安全的HTTPS协议。HTTPS是以安全为目标的HTTP通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。
登录信息
usr:pass表示的是登录认证信息,包括登录用户的用户名和密码。虽然登录认证信息可以在URL中体现出来,但绝大多数URL的这个字段都是被省略的,因为登录信息可以通过其他方案交付给服务器。
服务器地址
www.example.jp 表示的是服务器地址,也叫做域名,常见的比如www.baidu.com等。
域名等价于IP,用于标识一台主机在全网中的唯一性,域名实际还会做解析,解析之后就是服务器的IP地址,用域名不用IP主要是因为域名用起来方便,且更适合用户来看。
域名会和特定的IP地址做映射,比如我们可以用ping命令查看www.baidu.com的IP地址。

如果用户看到的是IP地址,那么用户在访问这个网站之前并不知道这个网站是干什么的,但是用户如果看到的是www.baidu.com这个域名,就知道是哪家公司等信息了。因此域名具有更好的自描述性。
实际我们可以认为域名和IP地址是等价的,在计算机当中使用的时候既可以用域名,也可以用IP地址。但URL呈现出来是让用户看的,*因此URL当中是以域名的形式表示服务器地址的。
服务器端口号
80表示的是服务器端口号,HTTP协议和套接字编程一样都是位于应用层的,在进行套接字编程时我们需要给服务器绑定对应的IP和端口,而这里的应用层协议同样也需要有明确的端口号。
服务器端口号在大部分情况下都可以省略,因为协议和端口号是强绑定的!所有的网络服务都有对应的端口号,这是已经确定好的。
浏览器是根据我们的协议来知晓服务器的端口号的,一般HTTP协议对应服务器的端口号为80,HTTPS对应服务器的端口号是443等。
带层次的文件路径
/dir/index.htm 表示的就是要访问资源的所在路径,访问服务器的本质目的是获取服务器上的某种资源,通过前面的域名和端口已经能够找到对应的服务器进程了,此时要做的就是指明该资源所在的路径。
比如我们打开了浏览器输入百度的域名之后,此时浏览器就帮我们获取到了百度的首页。

当我们发起网页请求时,本质是获得一张网页信息,然后浏览器对这张网页信息进行解释,最后就呈现出来对应的网页。
此外我们还会向服务器请求视频、音频、网页、图片等资源。HTTP之所以叫做超文本传输协议,而不叫做文本传输协议,就是因为有很多资源实际并不是普通的文本资源。
因此在URL就有这样一个字段,用于表示要访问的资源所在的路径。此外我们可以看到,这里的路径分隔符是 / ,而不是 \ ,这也就证明了实际很多服务器都是部署在Linux上的!
查询字符串
uid=1表示的是请求时提供的额外的参数,这些参数是以键值对的形式,通过 & 符号分割开的。
片段标识符
ch1表示的是片段标识符,是对资源的部分补充。
URLencode介绍
- 像 / 、 ? 、 : 这样的字符,已经被url当作特殊意义处理了,因此这样字符不能随意出现,如果某个参数中需要带有这些字符,就必须先对特殊字符进行转义,即URLencode。
- 一个中文字符由 UTF-8 或者 GBK 这样的编码方式构成,虽然在 URL 中没有特殊含义,但是仍然需要进行转义,否则浏览器可能把 UTF-8/GBK 编码中的某个字节当做 URL 中的特殊符号。
现在网络中有许多在线编码工具,这里我分享一个:在线编码工具
举个例子,当我们在百度中搜索C++时,由于 + 号在URL中也是特殊符号,而 + 字符转为十六进制后的值为 0x2B ,因此一个 + 就会被编码成一个 %2B。

我们打开上面我分享的解码工具,进行URLdecode(解码的意思)。

得到结果如下:

实际当服务器拿到对应的URL之后,也需要对编码后的参数进行解码,此时服务器才能拿到你想传递的参数,解码实际就是编码的逆过程。
3. HTTP协议格式
应用层常见的协议有HTTP和HTTPS,传输层常见的协议有TCP,网络层常见的协议是IP,数据链路层常见的协议是MAC数据帧。其中下三层是由操作系统或者驱动帮助我们完成的,它们主要负责通信细节。如果应用层不考虑下三层,它就可以认为自己是在和对方的应用层进行数据交互。

下三层负责是通信细节,而应用层负责的是如何使用传输过来的数据,两台主机在进行通信的时候,应用层的数据能够成功交给对端应用层,因为网络协议栈的下三层已经负责完成了这样的通信细节,而如何使用传输过来的数据就需要我们去定制协议,这里最典型的就是HTTP协议。
HTTP是基于请求和相应的应用层服务,作为客户端,你可以向服务器发起request,服务端接收到这个request之后,会对这个request做数据分析,得出你想要访问什么资源,然后服务器再构建response,完成这一次HTTP的请求。这种基于request&response这样的工作方式,我们称之为cs或bs模式,其中c表示client,s表示server,b表示brower。
由于HTTP是基于请求和相应的应用层访问,因此我们必须要知道HTTP对应的请求格式和响应格式,这也是学习HTTP的重点。
3.1 HTTP请求协议格式
HTTP请求格式如下:

HTTP请求由以下四部分组成:
- 请求行:请求方法+URL+HTTP版本
- 请求报头:请求的属性,这些属性都是以key:value的形式按行陈列的。
- 空行:遇到空行表示请求报头结束。
- 请求正文:请求正文允许为空字符串,如果请求正文存在,则在请求报头中会有一个Content-Length属性来标识请求正文的长度。
其中,前面三部分一般是HTTP协议自带的,是由HTTP协议自带的,是由HTTP协议自行设置的,而请求正文一般是用户的相关信息或数据,如果用户在请求时没有信息要上传给服务器,此时请求正文就为空字符串。
如何将HTTP请求的报头与有效载荷分离?
当应用层收到一个HTTP请求时,它必须想办法将HTTP的报头与有效载荷进行分离。对于HTTP请求来讲,这里的请求行和请求报头就是HTTP的报头信息,而这里的请求正文就是HTTP的有效载荷。
我们可以根据HTTP请求当中的空行来进行分离,当服务器收到一个HTTP请求之后,就可以按行进行读取,如果读取到空行则说明已经将报头读取完毕,实际HTTP请求当中的空行就是用来分离报头和有效载荷的。
如果将HTTP请求想象成一个大的线性结构,此时每行的内容都是用 \n 分开的,因此在读取过程中,如果连续读到两个 \n ,则说明已经将报头读取完毕了,剩下的就是有效载荷了。
获取浏览器的HTTP请求
在网络协议栈中,应用层的下一层叫做传输层,而HTTP协议底层通常使用的传输层是TCP协议,因此我们可以使用套接字编写一个TCP服务器,然后启动浏览器访问我们的这个服务器。
由于我们的服务器是直接用TCP套接字读取浏览器发来的HTTP请求,此时在服务端就没有应用层这个HTTP请求进行过任何解析,因此我们可以直接将浏览器发来的HTTP请求进行打印输出,此时就能看到HTTP请求的基本构成。
下面我们编写一个简单的TCP服务器。这个服务器要做的就是把浏览器发来的HTTP请求进行打印。
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>using namespace std;int main()
{// 创建套接字int listen_sock = socket(AF_INET, SOCK_STREAM, 0);if (listen_sock < 0){std::cerr << "socker error" << std::endl;exit(1);}// 绑定struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(8081);local.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){std::cerr << "bind error" << std::endl;exit(2);}// 监听if (listen(listen_sock, 5) < 0){std::cerr << "listen error" << std::endl;exit(3);}// 启动服务器struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);while (1){int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);if (sock < 0){std::cerr << "accept error" << std::endl;continue;}if (fork() == 0) // 爸爸进程{close(listen_sock);if (fork() > 0) exit(0);// 孙子进程char buffer[1024];recv(sock, buffer, sizeof(buffer), 0); // 获取HTTP请求std::cout << "-----------------------------http request begin-------------------------" << std::endl;std::cout << buffer << std::endl;std::cout << "-----------------------------http request end-------------------------" << std::endl;close(sock);exit(0);}// 爷爷进程close(sock);waitpid(-1, nullptr, 0);}close(listen_sock);return 0;
}
运行服务器之后,可以用浏览器进行访问,服务器会将收到的HTTP请求进行打印。

得到的结果如下:

说明:
- 浏览器向我们的服务器发起HTTP请求之后,因为我们的服务器没有对其进行响应,此时浏览器会认为服务器没有收到,然后再不断发起新的HTTP请求,因此我们浏览器虽然只访问了一次,但是服务器会收到多次HTTP请求。
- 由于浏览器发起请求时默认使用的就是HTTP协议,因此我们在浏览器的URL框中输入网址时可以不用指明HTTP协议。
- URL当中的 / 不能称之为我们云服务器上的根目录,这个 ==/==表示的是Web根目录,这个Web根目录可以是机器上的任何一个目录,这个是可以自己指定的,不一定就是Linux的根目录。
其中请求行中的URL一般是不携带域名以及端口号的,因为在请求报头的Host字段当中会进行指明,请求行中的URL表示你要访问这个服务器下哪一路径的资源。如果浏览器在访问我们的服务器时要指明访问的资源路径,那么此时浏览器发起的HTTP请求当中的URL也会跟着变成该路径。


请求报头当中全部都是以 key:value 形式按行陈列的各种请求属性,请求属性陈列完之后紧接着的就是一个空行,空行后的就是本次HTTP请求的请求正文,此时请求正文为空字符串,因此这里有两个空行。
3.2 HTTP响应协议格式
HTTP相应协议格式如下:

HTTP相应由以下四部分组成:
- 状态行:http版本+状态码+状态码描述。
- 响应报头:响应的属性,这些属性都是以key:value的形式按行陈列的。
- 空行:遇到空行表示相应报头结束。
- 响应正文:响应正文允许为空字符串,如果相应正文存在,则相应报头中会有一个Content-Length属性来标识响应正文的长度。比如服务器返回了html界面,那么这个html界面的内容就是在响应正文当中的。
如何将HTTP相应的报头与有效载荷分离?
对于HTTP响应来讲,这里的状态行和响应报头就是HTTP的报头信息,而这里的响应正文就是HTTP的有效载荷。与HTTP请求相同,当应用层收到一个HTTP响应时,也是根据HTTP响应当中的空行来分离报头和有效载荷的。当客户端收到一个HTTP响应后,就可以按行进行读取,如果读取到空行则说明报头已经读取完毕。
构建HTTP响应给浏览器
服务端读取到客户端发来的HTTP请求后,需要对这个HTTP请求进行各种数据分析,然后构建成对应的HTTP响应发回给客户端。而我们的服务器连接到客户端之后,实际就只读取了客户端发来的HTTP请求就将连接断开了。
接下来我们可以构建一个HTTP请求给服务区,鉴于现在还没有办法分析浏览器发来的HTTP请求,这里我们可以给浏览器返回一个固定的HTTP响应。我们就将当前服务程序所在路径作为Web根目录,我们可以在该目录下创建一个html文件,然后编写一个简单的html作为服务器的首页。

当浏览器向服务器发起HTTP请求时,不管浏览器发来的是什么请求,我们都将这个网页响应给服务器,此时这个html文件的内容就一个放在响应正文当中,我们只需读取该文件当中的内容,然后将其作为响应正文即可。
int main()
{// 创建套接字int listen_sock = socket(AF_INET, SOCK_STREAM, 0);if (listen_sock < 0){std::cerr << "socker error" << std::endl;exit(1);}// 绑定struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(8081);local.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){std::cerr << "bind error" << std::endl;exit(2);}// 监听if (listen(listen_sock, 5) < 0){std::cerr << "listen error" << std::endl;exit(3);}// 启动服务器struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);while (1){int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);if (sock < 0){std::cerr << "accept error" << std::endl;continue;}if (fork() == 0) // 爸爸进程{close(listen_sock);if (fork() > 0) exit(0);// 孙子进程char buffer[1024];recv(sock, buffer, sizeof(buffer), 0); // 获取HTTP请求std::cout << "-----------------------------http request begin-------------------------" << std::endl;std::cout << buffer << std::endl;std::cout << "-----------------------------http request end-------------------------" << std::endl;// 读取html文件内容ifstream in("index.html");if (in.is_open()){in.seekg(0, in.end);int len = in.tellg();in.seekg(0, in.beg);char* file = new char[len];in.read(file, len);in.close();// 构建HTTP响应std::string status_line = "http/1.1 200 OK\n"; // 状态行std::string response_header = "Content-Length" + to_string(len) + "\n"; // 响应报头std::string blank = "\n";std::string response_text = file; // 响应正文std::string response = status_line + response_header + blank + response_text; // 响应报文// 发出HTTP响应send(sock, response.c_str(), response.size(), 0);delete[] file;}close(sock);exit(0);}// 爷爷进程close(sock);waitpid(-1, nullptr, 0);}close(listen_sock);return 0;
}
当我们用浏览器访问服务器时,就会显示出对应的内容。


此外,我们通过telnet命令来访问服务器,也是能够得到这个HTTP响应的。

- 实际我们在进行网络请求的时候,如果不指明请求资源的路径,那么默认访问的就是目标网站的首页,也就是Web根目录下的index.html文件。
- 由于只是作为实例,我们在构建HTTP响应时,在响应报头当中只添加了一个属性Conten-Length,表示相应正文的长度,实际HTTP响应报头的属性信息还有很多。
使用HTTP协议为什么要交互版本?
HTTP请求当中的请求行和HTTP响应当中的状态行都包含了HTTP的版本信息。其中HTTP请求是由客户端发送的,因此HTTP请求当中表明的是客户端的HTTP版本,而HTTP响应是由服务器发送的,因此HTTP响应表明的是服务器的HTTP版本。
客户端和服务器双方在进行通信时会交互HTTP版本,主要还是为了兼容性的问题。因为服务器和客户端使用的可能是不同的HTTP版本,为了让不同版本的客户端都能享受到对应的服务,此时就要求通信双方进行版本协商。
客户端在发起HTTP请求时告诉服务器自己使用的HTTP版本,此时服务器就可以根据客户端使用的HTTP版本,为客户端提供对应的服务,而不至于因为双方使用的HTTP版本不同而导致无法正常通信。因此为了保证良好的兼容性,通信双方需要交互一些各自的版本信息。
4. HTTP的方法
HTTP常见方法如下:

其中最常用的就是GET方法和POST方法
GET方法一般用户获取某种资源,而POST方法一般用于将资源上床给服务器。但实际我们上传数据时也有可能使用GET方法,比如百度提交数据时实际用的就是GET方法。
GET方法和POST方法都可以带参:
- GET方法是通过URL传参的
- POST方法是通过正文传参的
从GET方法和POST方法的传参形式可以看出,POST方法能传递更多的参数,因为URL的长度是有限制的,POST方法通过正文传参就可以携带更多的数据。
此外,使用POST方法传参更加私密,因为POST方法不会将你的参数回显到URL当中,此时也就不会被别人轻易看到。不能说POST方法比GET方法更安全,因为GET方法和POST方法实际都不安全,要做到安全只能通过加密来实现。
说明:
- 当我们使用GET方法时,我们提交的参数会回显到URL当中,因此GET方法一般是处理数据不敏感的。
- 如果你要传递的数据比较私密的话一定要用POST方法,倒不是因为POST方法更安全,实际上GET和POST方法传参时都是明文传送,所以都不安全,但是POST方法更加私密,因为POST是通过正文传输的,不会将参数立马回显到浏览器的URL框中,所以相对更私密。
5. HTTP的状态码

我们最常见的一些状态码有:200(OK),404(Not Found),403(Forbidden请求权限不够),302(Redirect),504(Bad Gateway)。
Redirection(重定向状态码)
重定向就是通过这种方法将各种网络请求重新定个方向转到其他位置,此时这个服务器相当于提供了一个引路的服务。
重定向又分为临时重定向和永久重定向,其中状态码301表示的就是永久重定向,而状态码302和307表示的是临时重定向。
临时重定向和永久重定向本质是影响客户端的标签,决定客户端是否需要更新目标地址。如果某个网站是永久重定向,那么第一次访问该网站时由浏览器帮你进行重定向,但后续再访问该网站时就不需要浏览器再进行重定向了,此时你访问的直接就是重定向之后的网站。而如果某个网站是临时重定向的,那么每次访问该网站时如果需要进行重定向,都需要浏览器来帮我们完成重定向跳转到目标网站。
临时重定向演示
进行临时重定向时需要用到Location字段,Location字段是HTTP报头当中的一个属性信息,该字段表明了你所要重定向到的目标网站。
我们这里要演示临时重定向,可以将HTTP响应当中的状态码改为307,然后跟上对应的状态码描述,此外,还需要在HTTP响应报头中添加Location字段,这个Location后面跟的就是你需要重定向到的网页,比如我们将其设置为百度搜索的首页。
// 构建HTTP响应std::string status_line = "http/1.1 307 Temporary Redirect\n"; // 状态行std::string response_header = "Location: https://www.baidu.com/\n"; // 响应报头std::string blank = "\n"; // 空行std::string response = status_line + response_header + blank; // 响应报文// 响应HTTP请求send(sock, response.c_str(), response.size(), 0);
这样,如果我们用浏览器访问服务器,就会自动跳转到百度搜索的首页了。
此时当我们用telnet命令登录我们的服务器器时,向服务器发起HTTP请求,此时服务器给我们的响应就是状态码307,响应报头当中Location字段对应的就是百度搜索的地址。

6. HTTP的Header
HTTP常见的Header如下:
- Content-Tye:数据类型(text/html等)。
- Content-Length:正文的长度。
- Host:客户端告诉服务器,所请求的资源是在哪个主机的哪个端口上。
- User-Agent:表明用户的操作系统和浏览器的版本信息。
- Referer:当面页面是哪个页面跳转过来的。
- Location:搭配3XX状态码使用,告诉客户端接下来要去哪里访问。
- Cookie:用于在客户端存储少量信息,通常用于实现会话(session)的功能。
Host
Host字段表明了客户端要访问的服务器的IP和端口,比如当浏览器访问我们的服务器时,浏览器发来的HTTP请求当中的Host字段填的就是我们的IP和端口。但客户端不就是访问服务器吗?为什么客户端还要告诉服务器它要访问的服务对于的IP和端口?
因为有些服务器提供的是一种代理服务,也就是代理客户端向其他服务器发起请求,然后将请求得到的信息再返回给客户端。在这种情况下客户端就必须告诉代理服务器它要访问的服务对应的IP和端口,此时Host提供的信息就有效了。
- User-Agent
User-Agent代表的是客户端对应的操作系统和浏览器的版本信息。
比如当我们用电脑下载某些软件时,它会自动向我们展示与我们操作系统相匹配的版本,这实际就是因为我们在向目标网站发起请求的时候,User-Agent字段当中包含了我们的主机信息,此时该网站就会向你推送相匹配的软件版本。
Referer
Referer代表的是你当前从哪一个页面跳转过来的,Referer记录上一个页面的好处一方面是方便回退,另一方面可以知道我们当前页面与上一个页表之间的相关性。
Keep-Alive(长连接)
HTTP/1.0是通过request&response的方式来进行请求和响应的,HTTP/1.0常见的工作方式就是客户端和服务端先建立连接,然后客户端发起请求给服务端,服务器再对该请求进行响应,然后立马端口连接。
但如果一个连接建立后客户端和服务器只进行一次交互,就将连接关闭,就太浪费资源量,因此现在主流的HTTP/1.1是支持长连接的。所谓的长连接就是建立连接后,客户端可以不断地向服务器一次写入多个HTTP请求,而服务器在上层一次读取这些请求就行了,此时一条连接就可以传送大量的请求和响应,这就是长连接。
如果HTTP请求或响应报头当中的Connect字段对应的值是Keep-Alive,就代表支持长连接。
7. Cookie和Session
HTTP实际上是一种无状态协议,HTTP的每次请求/响应直接都是没有任何关系的,但你在使用浏览器的时候发现并不是这样的。
比如当你登录一次CSDN之后,就算你把CSDN网站关了甚至是重启电脑,再次打开CSDN,CSDN并没有要求你再次输入账号和密码,这实际上就是通过Cookie技术来实现的,点击浏览器当中锁的标志就可以看到对应网站的各种Cookie数据。

这些Cookie数据实际都是对应的服务器方写的,如果你将对应的某些Cookie删除,那么此时可能就需要你重新进行登录认证了,因为你删除的可能正好就是你登录时设置的Cookie信息。
Cookie是什么呢?
因为HTTP是一种无状态协议,如果没有Cookie的存在,那么每次我们要进行网页请求时都要重新输入账号和密码进行认证,这样太麻烦了。
比如你是某个视频网站的VIP,这个网站里面的VIP视频有很多,每次点击一个视频都要重新进行VIP身份认证,而HTTP不支持记录用户状态,那么我们就需要有一种独立技术来帮我们支持,这种技术目前已经内置到HTTP协议当中了,叫做Cookie。
当我们第一次登录某个网站时,需要输入我们的账号和密码进行身份认证,此时如果服务器经过数据对比之后判断你是一个合法的用户,那么为了让你后续在进行网页请求时不用重新输入账号和密码,此时服务器就会进行Set-Cookie的设置。(Set-Cookie也是HTTP报头当中的一种属性信息)。
当认证通过并在服务端进行Set-Cookie设置后,服务器在对浏览器进行HTTP响应时就会将这个Set-Cookie响应给浏览器。而浏览器收到响应之后会自动提取出Set-Cookie的值,将其保存在浏览器的Cookie的文件当中,此时相当于我的账号和密码信息保存在本地浏览器的Cookie文件当中。

从第一个登录认证之后,浏览器再向该网站发起的HTTP请求当中就会自动包含一个Cookie字段,其中携带的就是我第一次的认证信息,此后对端服务器需要对你进行认证时就会直接提取出HTTP请求当中的Cookie字段,而不会重新让你输入账号和密码了。
也就是在第一次认证登录后,后续所有的认证都变成了自动认证,这就叫做Cookie技术。
内存级别和文件级别
Cookie就是在浏览器当中的一个小文件,文件里记录的就是用户的私有信息。Cookie文件可以分为两种,一种是内存级别的Cookie文件,一种是文件级别的Cookie文件。
- 将浏览器关掉后再打开,访问之前登录过的网站,如果需要你重新输入账号和密码,说明你之前登录时浏览器当中保存的Cookie信息是内存级别的。
- 将浏览器关掉甚至将电脑重启再打开,访问之前登录过的网站,如果不需要你重新输入账号和密码,说明你之前登录浏览器时当中保存的Cookie信息是文件级别的。
Cookie被盗
如果浏览器当中保存的Cookie信息被非法盗取了,那么此时这个非法用户就可以用你的Cookie信息,以你的身份访问你曾经访问过的网站,我们将这种线程称为Cookie被盗取了。
比如你不小心点了某个链接,这个链接可能就是一个下载程序,当你点击之后它就会通过某种方式将程序下载到你本地,并且自动执行该程序,该程序会扫描你的浏览器当中的Cookie目录,把所有的Cookie信息通过网络的方式传送给恶意方,当恶意方拿到你的Cookie信息后就可以拷贝到它浏览器对应的Cookie目录当中,然后以你的身份访问你曾经访问过的网站。
SessionID的引入
单纯使用Cookie是不安全的,因为Cookie当中保存的是你的私密信息,一旦Cookie文件泄漏你的隐私信息也就泄漏。
所以当前主流的服务器还引入了SessionID这样的概念,当我们第一次登录某个网站输入账号和密码后,服务器认证成功之后还会在服务端生成一个对应的SessionID,这个SessionID与用户信息是不相关的。系统会将所有登录用户的SessionID值统一维护起来。
此时当认证通过后服务端在对浏览器进行HTTP响应时,就会将这个生成的SessionID值响应给浏览器。浏览器收到响应后自动提取出SessionID的值,将其保存在浏览器的Cookie文件当中。后续访问服务器时,对应的HTTP请求当中就会自动携带上这个SessionID。

而服务器识别到HTTP请求当中包含了SessionID,就会提取出这个SessionID,然后再到对应的集合当中进行对比,对比成功就说明这个用户是曾经登录过的,此时也就自动认证成功了,然后就会正常处理你发来的请求,这就是当前主流的工作方式。
安全也只是相对的
引入SessionID之后,浏览器当中对应的Cookie文件保存的是SessionID,此时这个Cookie文件同样可能被盗取。此时用户的账号和密码虽然不会泄漏了,但用户对应的SessionID是会泄漏的,非法用户仍然可以盗取我的SessionID去访问我曾经访问过的服务器,相当于还是存在上面所说的问题。
- 之前的工作方式就相当于把账号和密码信息在浏览器当中再保存一份,每次请求时都自动将账号和密码携带上,但是账号和密码一直在网络当中发送太不安全了。
- 因此现在的工作方式是,服务器只有在第一次认证的时候需要在网络中传输账号和密码,此后在网络中发送的都是SessionID。
这种办法虽然没有真正地解决安全问题,但是这种方法是相对安全的。互联网上是不存在绝对安全这样的概念的,任何安全都是相对的,就算你将发送到网络中的信息进行加密,也有可能被人破解。
不过在安全领域有一个准则:如果破解某个信息的成本已经远远大于破解之后获得的收益,那么可以说这个信息是安全的。
引入SessionID之后的好处
- 在引入SessionID之前,用户登录的账号信息都是保存在浏览器内部的,此时的账号信息是由客户端去维护的。
- 而引入SessionID之后,用户登录的账号信息都是由服务器去维护的,在浏览器内部保存的只是SessionID。
此时虽然SessionID可能被非法用户盗取,但服务器也可以使用各种各样的策略来保证用户账号的安全。
- IP是有归类的,可以通过IP地址来判断登录用户所在的地址范围。如果一个账号在短时间内登录地址发生了巨大变化,此时服务器就会立马识别到这个账号发生异常了,进而在服务器当中清除对应的SessionID的值。这时当你或那个非法用户想要访问服务器时,就都需要重新输入账号和密码进行身份认证,而只有你是知道自己的密码的,当你重新认证登录后服务器就可以将另一方识别为非法用户,进而对该非法用户进行对应的黑名单/白名单身份认证。
- 当操作者想要进行某些高权限的操作时,会要求操作者再次输入账号和密码信息,再次确认身份。就算你的账号被非法用户盗取了,但非法用户在你改密码时仍然需要输入旧密码,这是非法用户在短时间内无法做到的,因为它并不知道你的密码。
- SessionID也有过期策略,比如SessionIDS一个小时内有效的。所以即便你的SessionID被非法用户盗取了,也仅仅是在一个小时内有效,而且在功能上受约束,不会造成太大影响。
任何事情都有两面性,如果不是一些非法用户的存在,现在的服务器肯定是漏洞百出,只有双方不断进行对抗才能不断进步。
相关文章:
【计算机网络】应用层协议 -- HTTP协议
文章目录 1. 认识HTTP协议2. 认识URL3. HTTP协议格式3.1 HTTP请求协议格式3.2 HTTP响应协议格式 4. HTTP的方法5. HTTP的状态码6. HTTP的Header7. Cookie和Session 1. 认识HTTP协议 协议。网络协议的简称,网络协议是通信计算机双方必须共同遵守的一组约定࿰…...
了解Unity编辑器之组件篇Layout(八)
Layout:用于管理和控制UI元素的排列和自动调整一、Aspect Ratio Fitter:用于根据宽高比自动调整UI元素的大小 Aspect Mode:用于定义纵横比适配的行为方式。Aspect Mode属性有以下几种选项: (1)None…...
如何使用Flask-Mail来发送电子邮件
你知道如何使用Flask-Mail来发送电子邮件吗 Flask-Mail是一个用于Flask框架的扩展,它简化了在Flask应用程序中发送电子邮件的过程。通过使用Flask-Mail,你可以轻松地创建邮件消息对象,设置发件人、收件人、主题和正文,并使用SMTP服…...
【笔记】Java并发编程
为什么不建议使用Executors创建线程池分析 不建议使用Executors来创建线程池,主要是有两大原因第一个是问题回溯的问题,使用Executors都可以使用默认的情况,无法用户自定义线程名称不利于排查问题,第二个原因也是最主要原因就是线…...
Hive内部表和外部表
表类型详解 表分类 在Hive中,表类型主要分为两种 第一种:内部表 也叫管理表表目录会创建在集群上的{hive.metastore.warehouse.dir}下的相应的库对应的目录中。默认创建的表就是内部表 第二种:外部表 外部表需要使用关键字"external"ÿ…...
【面试题】与通义千问的芯片前端设计模拟面试归纳
这里是尼德兰的喵芯片设计相关文章,欢迎您的访问! 如果文章对您有所帮助,期待您的点赞收藏! 让我们一起为芯片前端全栈工程师而努力! 前言 两个小时,与chatGPT进行了一场数字IC前端设计岗的面试_尼德兰的喵的博客-CSDN博客 和GPT-3.5的回答可以对比品尝,味道更好。 模…...
无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。npm.ps1 cannot be loaded
目录 原因 解决方法 提示 查看当前的执行策略命令 改回默认值 "Restricted"命令 这个错误提示是因为您的系统禁止执行 PowerShell 脚本。 原因 现用执行策略是 Restricted(默认设置) 解决方法 以管理员身份运行 PowerShell:右键…...
Flowable-服务-Http任务
目录 定义图形标记XML内容界面操作 定义 Http 任务不是 BPMN 2.0 规范定义的官方任务,在 Flowable 中,Http 任务是作为一种特殊的服务 任务来实现的,主要调用Http服务使用。 图形标记 由于 Http 任务不是 BPMN 2.0 规范的“官方”任务&…...
Hexo+GithubPages免费搭建个人博客网站
HexoGithubPages免费搭建个人博客网站 目录 一、前言二、Github配置 新建同名仓库配置Pages 三、安装Hexo四、配置hexo-deployer-git五、访问六、发布文章七、安装主题 一、前言 我之前开了好几年的云服务器了,实际上使用场景并不是很多,感觉有点浪费…...
应用无线鼠标中的2.4GHz无线收发芯片
无线键盘和无线鼠标作为现代办公环境中常见的工具,为我们的工作带来了便利。无线键盘和无线鼠标的工作原理都是基于无线技术实现的,其中常见的是2.4GHz无线技术。让我们一起来详细了解一下它们的工作原理。 无线鼠标的原理非常简单,鼠标部分工作与传统鼠…...
Oracle 时间多少秒以后 oracle interval 多少分钟之前 Oracle日期1小时后 Java时间多少秒以后 Java日期多少天之前
Oracle 时间多少秒以后 oracle interval 多少分钟之前 Oracle日期1小时后 Java时间多少秒以后 Java日期多少天之前 一、概述 在项目开发中,遇到一个类似于 超时关闭的订单(超过1分钟后关闭订单) 的需求,在数据的时间写入时&#x…...
自动驾驶之轨迹规划8——Apollo参考线和轨迹
1. abstract 本文主要讲解routing和planning模块中的reference line,我之前一直搞不明白这个reference line是如何生成的,有什么作用,和routing以及planning的关系。现在有了一些心得打算梳理一下: 决策规划模块负责生成车辆的行…...
ES6 - promise.all和race方法的用法详解
文章目录 一、前言二、Promise.all()1,第一句:Promise.all()方法接受一个数组作为参数,且每一个都是 Promise 实例2,第二句:如果不是,就会先调Promise.resolve方法,将参数转为 Promise 实例再进…...
CAD .NET 15.0 企业版 Crack
CAD .NET 15.0 企业版 企业版 企业版 企业版 企业版 Updated: June 14, 2023 | Version 15.0 NEW CAD .NET is a library for developing solutions in .NET environment. It supports AutoCAD DWG/ DXF, PLT and other CAD formats. The library can be used in a wide rang…...
苍穹外卖day07——缓存菜品套餐+购物车功能实现
缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢,使用体验下降。 实现思路 使用redis缓存菜品数据,减少数据库查询操作。 页面展示上基本就是同一个分类在同一页,所以key-value结构可以使用不同的分…...
学习笔记|大模型优质Prompt开发与应用课(二)|第四节:大模型帮你写代码,小白也能做程序
文章目录 01软件开发产业趋势与技术革新软件开发产业趋势与技术革新技术性人才很受欢迎软件开发产业趋势与技术革新技术门槛越来越低 02 大模型驱动的软件开发需求分析prompt 产品设计开发和测试prompt输出回复promptpromptprompt回复 发布和部署promptprompt 维护和更新prompt…...
建造者设计模式 + 高阶函数 => DSL
该设计模式适用于创建复杂对象,该复杂对象通常是由各个部分的子对象用一定的算法或者步骤构成,针对每个子对象内部算法和步骤通常是稳定的,但是该复杂对象的确实由于不同的需求而选择使用不同的子对象进行组装。对于构建该复杂的对象…...
重学C++系列之智能指针简单介绍
一、什么是智能指针 在使用堆内存时,就像使用栈内存空间一样,可以实现自释放的功能,智能指针在C库中也是类模板之一。 二、智能指针有几种 有四种。auto_ptr, unique_ptr, shared_ptr, weak_ptr 其中后三个是C11支持,第一个已经被…...
LabVIEW开发航天器动力学与控制仿真系统
LabVIEW开发航天器动力学与控制仿真系统 计算机仿真是工程设计和验证的非常有用的工具。它节省了大量的时间、金钱和精力。航天器动力学与控制仿真系统由LabVIEW程序开发,它是模拟航天器等动态系统的有用工具。还可轻松与硬件连接并输出真实信号。 项目采用系统工…...
享元模式——实现对象的复用
1、简介 1.1、概述 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。例如,在一个文本字符串中存在很多重复的字符,如果每个字符都用一个单独的对象来表示,将会占用较多的内存…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
