当前位置: 首页 > article >正文

Linux网络之http协议

目录

URL

urlencode和urldecode

HTTP协议

HTTP协议的格式

如何理解/ 

HTTP请求方法

 POST和GET方法对比

HTTP常见header

HTTP响应状态码

3XX状态码

长链接和短链接 

cookies 

session 


在之前学习基于TCP的socket编程的时候,我们使用两种方法,实现了一个简单的计算器小程序。一种以结构化数据在客户端和服务器端之间进行网络传输,一种以序列化成字符串后的数据在客户端和服务器间进行网络传输。无论是上面的哪一种方案,只要能在客户端进行数据的正确发送,只要能在服务器端进行数据的正常解析接收,我们就称这是一种约定,也就称这是一种协议,这种协议是基于应用层程序员自己实现的一种协议。当然,在计算机网络中,已经拥有了一些实用,现成大佬们创建好的协议------HTTP协议(超文本传输协议),这便是我们本期的内容。

URL

URL:统一资源定位符,用于定位互联网上资源的地址。URL的组成部分为:协议,域名,路径,查询参数,片段

URL图示如下。 

 URL的作用是什么呢? 

我们知道,在计算机网络中,我们通过公网IP可以唯一确认一台主机,在一台主机上,我们可以通过路径确认一个文件资源,所以我们可以通过IP+路径确认一台主机上的一个文件资源。我们通常使用域名来表示一个IP,所以我们可以通过URL去访问一台主机上的一个资源。 

urlencode和urldecode

观察下图。

 为什么我们在搜索框中输入的是C++却在顶层的搜索框中出现了C%2B%2B的字符串呢?

在URL中我们有资源路径的概念,所以如果我们要检索的字符串中含有/这个字符,就必须对对应的字符进行特殊处理,即转义,转义的过程我们称为urlencode,反转义的过程我们称之为urldecode。 

转义的规则:一个字符为一个字节,一个字节就是8个bit位,而一个16进制位是4个bit位。所以我们对于一个字符,从右往左,进行转义,用一个16进制位替代4个bit位,不足补0直接处理,最终在转义的2个16进制位前加上%,这就是转移之后的字符。

下图为encode和decode的过程。 

HTTP协议

HTTP协议的格式

http请求如下。 

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

那么http请求主要由4部分组成,请求行,请求报头,空行,请求正文

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

http响应如下。

HTTP/1.1 200 OK
Date: Mon, 23 May 2022 22:38:34 GMT
Server: Apache/2.4.1 (Unix)
Last-Modified: Wed, 18 May 2022 15:17:12 GMT
Content-Length: 1234
Content-Type: text/html; charset=UTF-8
Connection: close

<!DOCTYPE html>
<html>
<head>
    <title>Example Page</title>
</head>
<body>
    <h1>Hello, World!</h1>
</body>
</html>

http响应也由4部分组成,状态行,响应报头,空行,响应正文

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

如何理解/ 

我们自己创建一个Http的服务器端。代码如下。

#include "Sock.hpp"
#include <pthread.h>
#include <string.h>
#include <unistd.h>

void *handle(void *args)
{
    pthread_detach(pthread_self());
    int fd = *(int *)args;
    delete (int *)args;

// 定义一个缓冲区,作为输出型参数,获取client端写入的数据
#define SIZE 1024 * 10
    char buffer[SIZE];
    memset(buffer, 0, sizeof(buffer));
    ssize_t s = recv(fd, buffer, sizeof(buffer), 0);
    if (s > 0)
    {
        buffer[s] = 0;
        // 查看读取的请求
        std::cout << buffer;

        // 对客户端进行回应

        std::string response = "http/1.0 200 OK\n";
        response += "Content-Type: text/plain\n"; // 文本类型为普通文本
        response += "\n";                         // 空行
        response += "yjd Made in China!";

        send(fd, response.c_str(), response.size(), 0);
    }
    close(fd);
    return nullptr;
}

int main(int args, char *argv[])
{
    if (args != 2)
    {
        return 1;
    }
    // 作为服务器端
    // 1.创建socket文件
    int Listen_fd = Socket::Sock();
    // 2.绑定IP和端口号
    Socket::Bind(Listen_fd, atoi(argv[1]));
    // 3.进行监听
    Socket::Listen(Listen_fd);
    // 4.持续的获取链接

    for (;;)
    {
        int newfd = Socket::Accept(Listen_fd);
        int *fd = new int(newfd);
        pthread_t pid;
        pthread_create(&pid, nullptr, handle, (void *)fd);
    }

    return 0;
}


我们知道无论是http的请求还是响应,协议的格式,都是以一行为分割。如第一行请求行,通过第一个\n可以判断到请求行读取结束,然后读取header,读到空行意味着读取结束,最终空行之后就是请求的正文。 我们可以将http请求和http响应的每一行作为一个字符串,然后将整体的字符串拼接成一个大的字符串然后在网络中进行传输。

在浏览器中访问服务器,前端界面,后端的请求和响应如下。

在http请求中,这个/到底代表什么?代表请求根路径的资源吗?

nonono,这个/表示响应表示请求的资源的主页。 一般情况下,在服务器端,会有一个资源根目录,在这个根目录里面的html文件我们一般称之为服务器的主页,当客户端请求获取/时,其实就是返回服务器端根目录下的html主页。

index.html代码如下。

<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h3>你好 老表</h3>
    </body>
</html>

HTTP请求方法

GET:

  • 用于请求指定资源。
  • 只用于获取数据,不应产生副作用。
  • 数据通过URL传递,长度有限。

POST

  • 用于提交数据到服务器,通常用于表单提交或文件上传。
  • 数据在请求体中发送,适合传输大量或敏感信息。

PUT

  • 用于更新或替换指定资源。
  • 如果资源不存在,可以创建新资源。

DELETE

  • 用于删除指定资源。

PATCH

  • 用于部分更新资源,仅发送需要修改的部分。

HEAD

  • 类似于GET,但只返回响应头,不返回响应体,用于获取资源的元信息。

OPTIONS

  • 用于获取服务器支持的HTTP方法或资源的通信选项。

TRACE

  • 用于回显客户端的请求,主要用于测试或诊断。

CONNECT

  • 用于建立到目标资源的隧道,通常用于SSL/TLS加密的HTTPS连接。

 一般情况下,网站只暴露三个方法:GET POST HEAD方法。

 POST和GET方法对比

我们以以下HTML代码举例,分别以GET和POST方法发送请求。

GET方法。

<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h5>hello 我是首页!</h5>

        <h5>hello 我是表单!</h5>

        <form action="/a/b/handler_from" method="GET">
            姓名: <input type="text" name="name"><br/>
            密码: <input type="password" name="passwd"><br/>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

POST方法。 

<!DOCTYPE html>

<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <h5>hello 我是首页!</h5>

        <h5>hello 我是表单!</h5>

        <form action="/a/b/handler_from" method="POST">
            姓名: <input type="text" name="name"><br/>
            密码: <input type="password" name="passwd"><br/>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

浏览器界面如下。 

总结:

GET方法:GET方法一般用于获取请求,大部分情况下都是获取请求,但是也可以用于发送请求,通过URL以参数拼接的方式将请求发送给服务器。

POST方法:POST方法一般用于发送请求,通过将参数放于http请求的正文从而实现将参数传递给服务器端。  

除此之外GET和POST方法还有什么差别吗?

  1. 两个参数提交参数的位置不同,POST方法比较私密 ,不会回显到浏览器URL的输入框,但是GET方法会会显到输入框,增加了被盗取的风险。
  2. GET方法通过URL传参,但是URL的大小是有限制的,不同浏览器的限制不同,POST方法由正文传参,一般没有大小限制。

两种方法如何选择呢? 

如果提交的参数比较少,就使用GET方法,否则就使用POST方法。 

HTTP常见header

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

HTTP响应状态码

 HTTP请求状态码大致分为5类。

  1. 1XX:information(信息性状态码),接收的请求正在处理。
  2. 2XX:Success(成功状态码),请求正常处理完毕。
  3. 3XX:Redirection(重定向状态码),需要进行附加操作以完成请求。
  4. 4XX:Client Error(客户端错误状态码),服务器无法处理请求。
  5. 5XX:Server Error(服务器错误状态码),服务器处理请求出错。

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

3XX状态码

3XX状态码主要分为两种,暂时重定向和永久重定向。

永久重定向:301.(网址更换,旧的网址更新成新的网址)。

临时重定向:302/307(注册之后会跳转到登录界面,点击支付跳转到支付界面这些都是临时重定向)。

无论是哪种重定向,都必须在HTTP响应的报文的header中表明location属性,告诉客户端,接下来要去哪里进行访问。

下图代码我们永久重定向到了百度官网。 

        std::string response = "http/1/1 301 Permanently moved \n";
        response+="Location: https://www.baidu.com/\n";
        response+="\n";
        send(fd,response.c_str(),response.size(),0);

长链接和短链接 

Http协议的底层还是使用Tcp协议进行通信的。Tcp协议通信的原理图示如下。

Tcp协议client客户端和sever服务器端进行交互主要分为五步:1.客户端建立链接2.客户端发送请求3.服务器端获取链接4.服务器端获取请求5.服务端发送响应6.服务器端关闭链接7.客户端获取响应。

打开百度新闻的主页。

百度新闻的网页,不难发现有很多的图片资源。一般情况下,Tcp协议建立并最终断开链接,这样一整个过程就加载一个资源,一个图片就是一个资源。当我们输入官网点击访问时,client会向sever发送一个http请求,同时底层通过Tcp协议建立一个链接,获取主页资源,同时sever获取到请求之后,返回了主页资源,最终关闭了链接,但是此时我们要注意,此时返回的知识主页,主页中的诸多资源还没有被加载出来,所以后续还会通过类似的建立链接,发送请求,获取请求,发送响应并关闭链接这些步骤,一步步的加载页面的所有资源,但是这样的方式效率极低,因为频繁的创建连接和关闭链接这些都是要消耗时间的,以上这种方法就是我们所谓的短链接的方式。

在http1.1版本中,支持了长链接的方式,就是第一次建立链接的时候,就一次性加载完主页面的所有资源,这样就极大的提高了效率。

简单来说,短链接就是建立一次链接加载一个资源;长链接就是建立一次链接,加载完所有资源。

cookies 

何为cookies?

谈cookies之前,我们再引入一个概念,我们称http协议是一个无状态的协议,什么是无状态的协议?就是当前的请求是和之前以及以后的请求是无关的,当前请求是完全独立的,之间的请求进行了什么操作,之后的请求进行什么操作,都与本次请求无关。

在某站主页,我们打开登录界面,输入自己的账号和密码,建立一个http请求,最终服务器端进行了匹配之后,响应返回了当前用户的主页。如果当前用户是一个vip用户,那么此时就可以点击主页某块vip视频进行观看。我们知道点击这块vip视频之后,跳转到当前vip视频的播放界面,就又是一个http请求。那么问题来了。在登录界面我们输入了用户名和密码,最终发送了http请求,加载了当前vip用户的主页。那么为什么在当前vip用户的主页点击vip视频之后,我们没有输入用户名和密码,同样的通过http请求获取到了当前用户vip视频的播放界面。如果按照我们前面所说,http请求是无状态的,那么为什么第二次http请求仍然可以加载到当前vip用户vip视频播放界面,这不是违反了http协议是无状态的协议这一规则吗?

   其实,这并没有违反这一规则,这是因为cookies的功劳。cookies本质就是浏览器中的一个文件,这个文件是由sever端在http响应报文的header中通过set_cookies这一属性设置好对应的字段之后,发送响应报文,最终在client端浏览器页面生成对应的cookies文件。

  所以当我们在登录注册界面输入了账号和密码之后,点击登录按钮,client端携带账户和密码发送了http请求,sever端接收到请求之后,将账户和密码在后端数据库进行查询,如果匹配上就会在sever端建立响应,并且在http响应报文的header中通过set_cookies属性设置好当前用户的用户名和密码字段,最终将http响应报文返回client端,供client端进行解析,并且在client端创建cookies文件,cookies文件中的内容就是在http响应报文的set_cookies中设置的字段,即用户的账号和密码。

上图为一个简单的cookies生成展示。

通过上述知识,我们就可以解释我们刚开始的现象,当一个vip用户登录账号成功并且进入主页之后,那么此时浏览器主页就生成了一个cookies文件,里面保存当前用户的账号和密码,所以之后的页面跳转(即每次http请求)都会在报文的header中携带cookies信息,直接会拿cookies中的用户信息与数据库中的进行匹配,从而省去频繁的登录(获取账号和密码)操作,提高网站的可用性。http协议仍然是无状态的,但是通过报文中header的cookies字段实现了多个http协议的“关联性”。

总的来说:1.cookies就是一个文件,里面存储用户的私密信息。

                  2.一旦网页中有cookies信息,那么以后得每次请求,在请求报文的header中都会有cookies这一属性,存放用户的私密信息。

引入了cookies的概念之后,确实是提升了网站跳转的效率,但是同时也增加了风险。

  1. 既然在客户端生成了cookies文件,那么就有可能会被恶意分子去盗取这个文件,从而获取到用户的私密信息,即账号和密码。
  2. 既然会获取到cookies文件,那么当恶意分子加载到对应的网站就有可能直接通过cookies信息直接访问到对应的网页,从而对用户的账号进行破坏。

基于此,我们又引入了session的概念。

session 

session可以理解为是cookies的进化版本。

我们不是害怕不法分子盗用用户的账号和密码吗?那我们不在cookies中保存用户的账号和密码不就行了,我们保存的是一个session_id,这个session_id是唯一的,一个用户只有一个。图示如下。

当用户点击登录按钮,client端发送http请求(传递用户的参数,即账号和密码),sever端接收到http请求之后,将用户参数与数据库中参数进行比对,如果比对成功,此时会在response报文的header中设置set_cookies属性为一个session_id,这个id在sever的磁盘中对应了一个名为id的session文件,在文件中保留了用户的账号和密码,然后sever将response传给client,client会在浏览器界面创建一个cookies文件,保存了set_cookies中设置的session_id。此后的每次请求的报文header中都会有cookies属性携带浏览器文件中的session_id。之后的每次请求的用户参数,都会通过cookies属性中的session_id去与sever磁盘中的对应的文件匹配,匹配到之后,再用里面的用户参数去数据库中进行比对,比对成功则加载对应的界面。

总的来说,session和cookies一样也是一个文件,不过这个文件的名称是一个session_id,里面保存的是用户的私密信息。

引入session之后,避免非法人员获取用户账号和密码泄露这一风险,但是通过cookies访问页面这一风险没有解决,虽然没有解决,但是仍然有其它的方法规避这一风险,大家有兴趣可以去网上查找了解一下。

以上便是本期http协议的所有内容。

本期内容到此结束^_^


http://www.kler.cn/a/539395.html

相关文章:

  • WPS如何接入DeepSeek(通过JS宏调用)
  • MongoDB 有哪些特性
  • EasyExcel 导出合并层级单元格
  • at coder ABC 392
  • 4G核心网的演变与创新:从传统到虚拟化的跨越
  • 10vue3实战-----实现登录的基本功能
  • Docker安装pypiserver私服
  • Jupyter Notebook 6/7 设置代码补全
  • Windows图形界面(GUI)-QT-C/C++ - QT 文本编辑控件详解
  • 旋转位置编码(RoPE)讲解和代码实现
  • < OS 有关 > Ubuntu 版本升级 实践 24.04 -> 24.10, 安装 .NET
  • Ranger 2.1.0 Admin安装
  • 处理数据及其选择关键列进行一次聚类
  • 【前端基础】深入解析JavaScript中的编译原理、内存管理、垃圾回收机制和正则表达式
  • 深度学习中的Checkpoint是什么?
  • 软件工程与土木工程的不同
  • uniapp访问django目录中的图片和视频,2025[最新]中间件访问方式
  • DeepSeeek如何在Window本地部署
  • 全面的生成式语言模型学习路线
  • MySQL的字段类型
  • Django开发入门 – 0.Django基本介绍
  • 【Matlab优化算法-第13期】基于多目标优化算法的水库流量调度
  • SQL中 的exists用法
  • 用户管理(MySQL)
  • Rust语言的计算机基础
  • 畅快使用DeepSeek-R1的方法