http协议

HTTP简介

image-20240523221518145

超文本传输协议(HTTP)是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 遵循经典的客户端—服务端模型,客户端打开一个连接以发出请求,然后等待直到收到服务器端响应。HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。

学习HTTP要学习的点

image-20240524111615057

URL

HTTP 请求的内容通称为"资源"。"资源"可以是图片、文件等,每一个资源都有一个URL(统一资源定位符)进行标识。

//URL
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument
  1. **http://**告诉浏览器采用什么协议,浏览器也知道如何处理协议
  2. www.example.com:是一个域名,指示需要向网络中哪台主机发起请求。也可以用IP来表示。
  3. 80:端口。表示访问web服务器上资源的门(通道)。如果访问的该 Web 服务器使用 HTTP 协议的标准端口(HTTP 为 80,HTTPS 为 443)授予对其资源的访问权限,则通常省略此部分。否则端口就是 URI 必须的部分。
  4. /path/to/myfile.html:web服务器上资源的路径
  5. key1=value1&key2=value2#SomewhereInTheDocument:提供给 Web 服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。Web 服务器可以在将资源返回给用户之前使用这些参数来执行额外的操作。每个 Web 服务器都有自己的参数规则,想知道特定 Web 服务器如何处理参数的唯一可靠方法是询问该 Web 服务器所有者。
  6. #SomewhereInTheDocument:资源本身的某一部分的一个锚点。锚点代表资源内的一种“书签”,它给予浏览器显示位于该“加书签”点的内容的指示。例如,在 HTML 文档上,浏览器将滚动到定义锚点的那个点上;在视频或音频文档上,浏览器将转到锚点代表的那个时间。值得注意的是 # 号后面的部分,也称为片段标识符,永远不会与请求一起发送到服务器。报头和有效载荷是通过“\N区分”

HTTP概述

HTTP是一种应用层的协议,通过 TCP,或者是TLS——一种加密过的 TCP 连接——来发送,当然,理论上来说可以借助任何可靠的传输协议。

image-20240523222455814

每个请求都会被发送到一个服务端,它会处理这个请求并提供一个称作响应的回复。在客户端与服务端之间,还有许许多多的被称为代理的实体,履行不同的作用,例如充当网关或缓存

image-20240523222539424

在浏览器和处理其请求的服务器之间,还有路由器、调制解调器等等许多计算机。归功于 Web 的分层设计,这些机器都隐藏在网络层和传输层内。而 HTTP 位于这些机器之上的应用层。

客户端

为了展现一个网页,浏览器需要发送最初的请求来获取描述这个页面的 HTML 文档。接着,解析文档,并发送数个其他请求,响应地获取可执行脚本、展示用的布局信息(CSS)以及其他页面内的资源(一般是图片和视频等)。然后,浏览器将这些资源整合到一起,展现出一个完整的文档,即 Web 页面。之后的阶段,浏览器中执行的脚本可以获取更多资源,同时浏览器相应地更新网页。

一个 Web 页面是一个超文本文档。这意味着有一部分展示的内容会是链接——可以被激活(通常是点击鼠标)来获取一个新的网页——用户可以通过这些链接指示用户代理并进行网络浏览。浏览器会将收到的指示转换成 HTTP 请求,并进一步解析 HTTP 响应,向用户提供清楚的回复。

服务端

在上述通信过程的另一侧是服务端,它负责提供客户端所请求的文档。一个服务器可以不仅仅只有一台机器,而多个服务端软件实例也可部署在同一台机器上。利用 HTTP/1.1 和 Host 标头,它们甚至可以共用同一个 IP 地址。

代理

在浏览器和服务器之间,有许多计算机和设备参与传递了 HTTP 消息。依靠 Web 技术栈的层次化的结构,传递过程中的多数操作都位于传输层、网络层或物理层,它们对于 HTTP 应用层而言就是透明的,并默默地对网络性能产生着重要影响。还有一部分实体在应用层参与消息传递,一般被称为代理(Proxy)。代理可以是透明的,即转发它们收到的请求并不做任何修改,也可以表现得不透明,将它传递给服务端之前使用一些手段修改这个请求。代理可以发挥很多种作用:

  • 缓存(可以是公开的也可以是私有的,如浏览器的缓存)
  • 过滤(如反病毒扫描、家长控制…)
  • 负载均衡(让多个服务器服务不同的请求)
  • 认证(控制对不同资源的访问)
  • 日志(使得代理可以存储历史信息)

HTTP的性质

  1. HTTP 是可扩展的

    在 HTTP/1.0 中引入的 HTTP 标头(header)让协议扩展变得非常容易。只要服务端客户端之间对新标头的语义经过简单协商,新功能就可以被加入进来。

  2. HTTP 无状态,但并非无会话

    HTTP 是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连贯的交互,比如在电商网站中使用购物车功能。尽管 HTTP 根本上来说是无状态的,但借助 HTTP Cookie 就可使用有状态的会话。利用标头的扩展性,HTTP Cookie 被加进了协议工作流程,每个请求之间就能够创建会话,让每个请求都能共享相同的上下文信息或相同的状态。

HTTP流

当客户端想要和服务端——不管是最终的服务端还是中间的代理——进行信息交互时,过程表现为下面几步:

  1. 打开一个 TCP 连接:TCP 连接被用来发送一条或多条请求,以及接受响应消息。客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的 TCP 连接连向服务端。
  2. 发送一个 HTTP 报文:HTTP 报文(在 HTTP/2 之前)是语义可读的。在 HTTP/2 中,这些简单的消息被封装在了帧中,这使得报文不能被直接读取,但是原理仍是相同的。
  3. 读取服务端返回的报文信息:
  4. 关闭连接或者为后续请求重用连接。

HTTP报文

HTTP 请求和响应具有相似的结构,由以下部分组成:

  1. 一行起始行用于描述要执行的请求,或者是对应的状态,成功或失败。这个起始行总是单行的。
  2. 一个可选的 HTTP 标头集合指明请求或描述消息主体(body)。
  3. 一个空行指示所有关于请求的元数据已经发送完毕。
  4. 一个可选的包含请求相关数据的主体(比如 HTML 表单内容),或者响应相关的文档。主体的大小有起始行的 HTTP 头来指定。

起始行和 HTTP 消息中的 HTTP 头统称为请求头,而其有效负载被称为消息主体。

image-20240524091834315

HTTP请求

image-20240523223521096

起始行

起始行包含三个元素:

  1. HTTP 方法,一个动词(像 GETPUT 或者 POST)或者一个名词(像 HEAD 或者 OPTIONS),描述要执行的动作。例如,GET 表示要获取资源,POST 表示向服务器推送数据(创建或修改资源,或者产生要返回的临时文件)。
  2. 请求目标(request target),通常是一个 URL,或者是协议、端口和域名的绝对路径,通常以请求的环境为特征。请求的格式因不同的 HTTP 方法而异。
  3. HTTP 版本(HTTP version),定义了剩余消息的结构,作为对期望的响应版本的指示符。

Header

不区分大小写的字符串,紧跟着的冒号(':')和一个结构取决于标头的值。整个标头(包括值)由一行组成,这一行可以相当长。

有许多请求标头可用,它们可以分为几组:

image-20240524092641570

body

请求的最后一部分是它的主体。不是所有的请求都有一个主体:例如获取资源的请求,像 GETHEADDELETEOPTIONS,通常它们不需要主体。有些请求将数据发送到服务器以便更新数据:常见的情况是 POST 请求(包含 HTML 表单数据)。

HTTP响应

HTTP 响应报文的一个例子:

image-20240523224047506

响应报文包含了下面的元素:

  • HTTP 协议版本号。
  • 一个状态码(status code),表明请求是成功或失败。常见的状态码是 200404302
  • 一个状态信息,一个简短的,纯粹的信息,通过状态码的文本描述,帮助人们理解该 HTTP 消息。
  • HTTP 标头,与请求标头类似。
  • 响应的最后一部分是主体。不是所有的响应都有主体:具有状态码(如 201204)的响应,通常不会有主体。

image-20240524093009312

HTTP代码演示

在同一个路径下创建了一个叫wwwroot里面有一个index.htmld的文件放演示首页的代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <h5>http代码演示</h5>
    <!-- 验证pos / get方法 -->
    <form action="/" method="POST"> 
        姓名: <input type="text" name="name"><br/>
        密码: <input type="password" name="passwd"><br/>
        <input type="submit" value="登陆"> 
    </form>
</body>
</html>

http.cpp

#include"Sock.hpp"
#include<pthread.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fstream>

// wwwroot 就叫做web根目录,该目录下的东西就是访问的资源
// wwwroot目录下的index.html就叫做网站的首页
#define WWWROOT "./wwwroot/"
#define HOME_PAGE "index.html"

using namespace std;
void Usig(std::string proc)
{
    cout<<"Usig: "<<proc <<"prot"<<endl;
}

void* HandlerHttpRequest(void *args)
{
    int sock=*(int* )args;
    delete (int* )args;
    pthread_detach(pthread_self());

    char buffer[1024*10];
    memset(&buffer,0,sizeof(buffer));

    ssize_t s=recv(sock,buffer,sizeof(buffer),0);
    if(s>0)
    {
        buffer[s]=0;

        //返回网页信息包括http请求
        string html_file = WWWROOT;
        html_file += HOME_PAGE;
        ifstream in(html_file); //打开网络文件 为什么能打开呢?

        if(!in.is_open())
        {
    
            string http_response = "http/1.0 404 NOT FOUND\n";
            http_response += "Content-Type: text/html;charset=utf8\n";//正文类型
            http_response += "\n";
            http_response += "<html><p>你访问的资源不存在</p><html>";
            send(sock, http_response.c_str(), http_response.size(),  0);
        }

        else
        {
            struct stat st; //包含文件属性的结构体
            stat(html_file.c_str(), &st);//stat函数是用来获取文件的各种属性
            //http版本
            string http_response = "http/1.0 200 ok\n";
            正文部分的数据类型
            http_response += "Content-Type:text/html;charset=utf8\n";
            http_response += "Content-Length: ";
            http_response += std::to_string(st.st_size);
            http_response += "\n";

            //Set-Cookie:服务器向浏览器设置一个cookie
            //每次请求都会发送过去
            http_response+="Set-Cookie:id=222222\n";
            http_response+="Set-Cookie:password=222222\n";
            http_response+="\n";
            
            //正文信息
            string content;
            string line;
            while(getline(in, line))
            {
                content += line;
            }
            http_response += content;
            in.close();
            send(sock,http_response.c_str(),http_response.size(),0);

        }

    }
    close(sock);
    return nullptr;
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usig(argv[0]); exit(1);
    }

    uint16_t prot=atoi(argv[1]);
    int listen_sock=Sock::Socket();
    Sock::Bind(listen_sock,prot);
    Sock::Listen(listen_sock);

    for(;;)
    {
        int sock=Sock::Accept(listen_sock);
        if(sock>0)
        {
            pthread_t tid;
            int *parm=new int(sock);
            pthread_create(&tid,nullptr,HandlerHttpRequest,parm);
        }
    }

    return 0;
}

验证POST和GET方法

HTTP的GET方法通常用于从服务器请求数据。当使用GET方法时,参数可以附加到URL的查询字符串中。

image-20240524110152911

HTTP的POST方法通常用于向服务器发送数据,特别是当发送的数据量较大或包含敏感信息时。与GET方法不同,POST请求的数据不会作为URL的一部分,而是包含在HTTP的Body中

image-20240524110324660

向服务器发送数据(通常使用POST或PUT方法)

  • 目的:主要用于提交数据到服务器,如提交表单数据、上传文件或更新资源。
  • 数据格式:数据通常包含在HTTP请求体中,可以是文本(如HTML表单数据、JSON、XML等)或二进制数据(如文件)。
  • 安全性:POST和PUT请求通常不会将数据暴露在URL中,因此在一定程度上比GET请求更安全。然而,它们仍然需要通过HTTPS来确保数据的加密传输,以防止中间人攻击。
  • 幂等性:PUT方法是幂等的,意味着多次执行相同的PUT请求通常不会产生副作用(除了可能导致的更新冲突)。POST方法通常不是幂等的,每次执行都可能产生不同的结果。

向服务器请求数据(通常使用GET方法)

  • 目的:主要用于从服务器检索资源,如HTML页面、图像、数据记录等。
  • 数据格式:数据通常作为URL的查询字符串(query string)附加到URL上,或者作为HTTP头(如cookies、认证令牌等)发送。请求体通常不包含数据(除了某些特殊情况,如POST请求重定向为GET请求时)。
  • 安全性:由于数据暴露在URL中,GET请求可能不如POST或PUT请求安全。敏感信息(如密码、API密钥等)应避免使用GET方法发送。此外,GET请求应被视为幂等的,即多次执行相同的GET请求不应产生副作用。
  • 幂等性:GET方法是幂等的,意味着多次执行相同的GET请求将返回相同的结果(不考虑缓存和服务器状态变化等因素)。

其他注意事项

  • 缓存:GET请求的结果可以被缓存,而POST请求通常不会被缓存(除非特别指定)。这可能会影响性能和网络带宽使用。
  • 请求大小限制:由于URL长度的限制,GET请求可以发送的数据量通常比POST请求小。POST请求可以发送大量数据,具体取决于服务器配置和HTTP规范。
  • 日志记录:GET请求的URL(包括查询字符串)可能会被记录在服务器日志中,而POST请求的请求体通常不会。这可能会影响隐私和安全性。
  • 重定向:POST请求在重定向时通常会丢失请求体中的数据(除非使用特定的HTTP状态码和服务器配置),而GET请求可以安全地重定向,因为所有数据都包含在URL中。

响应状态码

HTTP 响应状态码用来表明特定 HTTP 请求是否成功完成。 响应被归为以下五大类:

  1. 信息响应 (100199)收到的请求正在处理
  2. 成功响应 (200299)请求正常处理完成
  3. 重定向消息 (300399)需要进行附加操作以完成请求
  4. 客户端错误响应 (400499)服务器无法处理请求
  5. 服务端错误响应 (500599)服务器处理请求出错

(404 Not Found)

服务器找不到请求的资源。在浏览器中,这意味着无法识别 URL。在 API 中,这也可能意味着端点有效,但资源本身不存在。服务器也可以发送此响应

重定向

在 HTTP 协议中,重定向操作由服务器向请求发送特殊的重定向响应而触发。重定向响应包含以 3 开头的状态码,以及 Location 标头,其保存着重定向的 URL。

浏览器在接收到重定向时,它们会立刻加载 Location 标头中提供的新 URL。除了额外的往返操作中会有一小部分性能损失之外,重定向操作对于用户来说是不可见的。

image-20240524095645225

不同类型的重定向映射可以划分为三个类别:

  1. 永久重定向
  2. 临时重定向
  3. 特殊重定向

永久重定向

这种重定向操作是永久性的。它表示原 URL 不应再被使用,而选用新的 URL 替换它。搜索引擎机器人、RSS 阅读器以及其他爬虫将更新资源原始的 URL。

image-20240524095901625

临时重定向

有时候请求的资源无法从其标准地址访问,但是却可以从另外的地方访问。在这种情况下,可以使用临时重定向。

image-20240524100018708

特殊重定向

304(Not Modified)会使页面跳转到本地的缓存副本中(可能已过时),而 300(Multiple Choice)则是一种手动重定向:将消息主体以 Web 页面形式呈现在浏览器中,列出了可能的重定向链接,用户可以从中进行选择。

image-20240524100202659

HTML的重定向meta

借助 HTML 的 元素的 HTML 重定向机制

<meta http-equiv="Refresh" content="0; URL=http://example.com/" />

由于存在上述几种 URL 重定向机制,那么在多种方法同时设定的情况下,哪种方法会首先起作用呢?

  1. HTTP 协议的重定向机制永远最先触发——它们甚至在没有传输页面的情况下就已经存在。
  2. HTML 的重定向机制 会在没有任何 HTTP 协议重定向的情况下触发。
  3. JavaScript 的重定向机制总是作为最后诉诸的手段,并且只有在客户端开启了 JavaScript 的情况下才起作用。

重定向死锁(循环)

当后续的重定向路径重复之前的路径的时候,重定向循环就产生了。换句话说,就是陷入了无限循环当中,不会有一个最终的页面返回。

大多数情况下,这属于服务器端错误。如果服务器检测不到,就会返回 500 Internal Server Error。假如你在修改了服务器配置不久就出现了这个问题,八成是遇到了重定向循环。

Cookie

Cookie是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器——如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

Cookie 主要用于以下三个方面:

Session

当用户访问一个网站并与之交互时,服务器会为该用户创建一个Session,并在服务器上存储与该用户相关的会话数据。这个Session通常与一个唯一的Session ID相关联,该ID通过Cookie或其他机制(如URL重写)传递给客户端,以便在后续的请求中识别用户。

Session可以存储任何类型的数据,包括字符串、数字、对象等。这使得Session非常适合用于存储与特定用户会话相关的状态信息,如登录状态、购物车内容、用户偏好等。

由于Session数据存储在服务器上,因此相对于存储在客户端的Cookie来说,Session具有更高的安全性。然而,仍然需要采取适当的安全措施来保护Session数据免受未经授权的访问和篡改,如使用HTTPS协议进行通信、设置合适的Session超时时间等。

服务器负责管理Session的创建、读取、更新和销毁。当用户关闭浏览器或会话超时时,服务器会销毁与该用户相关联的Session数据。此外,服务器还可以根据需要创建新的Session或终止现有的Session。

HTTPS

HTTP 协议的加密版本。它使用 SSLTLS 协议来加密客户端和服务器之间所有的通信。安全连接允许客户端与服务器安全地交换敏感数据,例如网上银行或者在线商城等涉及金钱的操作。

所有现代浏览器都支持 TLS 协议,它们都要求服务器提供一个有效的digital certificate(数字证书)来确认身份以建立安全连接。如果客户端和服务器都能提供自己的数字证书,则它们可以互相认证。

HTML标签不在网页上显示?

网页上只显示内容而HTML标签不会显示,这是因为浏览器在渲染网页时负责解析HTML文档,并将其转换为可视化的页面。HTML标签本身不是用来显示的,而是用来定义网页结构和内容的。浏览器会读取HTML文档中的标签,并根据这些标签的语义和属性来决定如何显示内容。

  • 15
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值