超详细的HTTP协议

2021/6/27 0:00:30

本文主要是介绍超详细的HTTP协议,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • HTTP协议是什么?
  • HTTP协议格式
    • 请求行
      • 请求方法
      • URL
      • 协议版本
        • HTTP0.9
        • HTTP1.0
        • HTTP1.1
          • 长连接
          • 管道机制
          • 分块传输
        • HTTP2.0
    • 响应行
    • 头部
    • Cookie与Session
      • Cookie
      • Session
      • Cookie与Session的区别
    • 空行
    • 正文
    • 简单的http服务器的搭建
  • 输入URL后发生了什么


HTTP协议是什么?

HTTP:超文本传输协议。HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同, 用于客户端和服务器之间的通信。请求访问文本或图像等资源的一端称为客户端, 而提供资源响应的一端称为服务器端。

  • http是一个明文字符串传输协议

  • http在传输层基于tcp协议实现

  • http是一个简单的请求-响应协议

HTTP协议格式

首行:请求行,响应行

头部:对于请求或者响应或者正文的一些关键描述。由一个个键值对key:空格value组成,每个键值对以\r\n结尾

空行:\r\n,间隔头部与正文

正文:客户端提交给服务端,或者服务端响应给客户端的数据

请求信息:
在这里插入图片描述响应信息:
在这里插入图片描述
采用的工具是Fiddler。Fiddler是一个HTTP调试抓包工具,它能记录所有客户端和服务器的http和https请求。

请求行

请求行:请求方法空格URL空格协议版本\r\n
在这里插入图片描述

请求方法

GET:从服务端获取实体资源,请求没有正文,但是也可以提交数据,提交的数据没有在正文中而是在URL中。

GET方法缺陷:

GET提交数据不安全。提交的数据在URL中,URL可见,所以不安全。

URL长度有限制。在早期,长度限制是1KB,现在长度限制是4KB或者8KB。

HEAD: 功能与GET类似。GET在服务器响应时,会有正文部分。而HEAD在服务器响应时,没有正文部分。

POST: 向服务端提交数据,请求有正文,数据放在正文中。
在这里插入图片描述
其他请求方法:
在这里插入图片描述

URL

URL:统一资源定位符,用于定位网络中某个主机上的某个资源。也就是我们所说的网址。

URL组成:协议名称://用户民:密码@域名:端口/资源路径?查询字符串#标识
在这里插入图片描述用户名与密码容易暴露信息,不安全,所以现在的URL中不写用户名和密码。http的默认使用80端口,https默认使用443端口。

域名: 服务器别名。最终访问服务器需要经过域名解析得到服务器IP。一个URL中,也可以直接使用IP地址作为域名使用。

/资源路径: 请求这个路径下的资源。这个路径是一个相对根目录。

查询字符串: 提交给服务器的数据。由一个个key=value形式键值对组成,键值对之间以&符号间隔。

用户请求的资源路径,或者查询字符串中存在特殊字符,则有可能与url中的特殊字符冲突,所以采用urlencode编码方式进行编码。

urlencode编码:将特殊字符每个字节转换为16进制数字字符,并前缀%

urldecode解码:遇到%则认为紧随其后的两个字符进行了编码,将这两个字符转化为数字。

示例:
在这里插入图片描述根据上图所示,我们要查询的数据是c++,而’+'的ASCII码值是43,转换为16进制就是2B,并且前缀%,就是url中的数据c%2B%2B。

协议版本

HTTP协议总共经过了0.9、1.0、1.1、2.0版本。

HTTP0.9

最早期的版本,只支持GET方法,只支持超文本数据传输(仅能请求访问HTML格式的资源)。

HTTP1.0

在0.9版本上做了改进,规范了http协议格式,增加了请求方式POST和HEAD;不再局限于0.9版本的HTML格式,支持各种多媒体资源传输;支持简单的缓存机制,就是当客户端在规定时间内访问同一网站,直接访问cache即可。

但是1.0版本的工作方式是每次TCP连接只能发送一个请求,当服务器响应后就会关闭这次连接,下一个请求需要再次建立TCP连接。这就是所谓的短连接。TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢。所以HTTP1.0版本,性能较差。随着网页需要加载的资源越来越多,这个问题就愈发突出。

HTTP1.1

更多的是对1.0版本进行性能的优化,支持了更多请求方法以及特性。比如说:支持长连接、更加完善的缓存控制、分块传输、管道机制等。

长连接

Connection:用于控制长连接的打开关闭状态 keep-alive/close

1.1版本的最大变化,就是引入了长连接,即TCP连接默认不关闭,可以被多个请求复用。一个TCP连接可以允许多个HTTP请求。使用长连接的HTTP协议,会在响应头加入Connection: keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。若客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。

  • 实现长连接需要客户端和服务端都支持长连接。
  • HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
  • 目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
管道机制

1.1版本还引入了管道机制,即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。
在这里插入图片描述
举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。

服务端是按队列顺序处理请求的,服务器只有处理完一个回应,才会进行下一个回应。假如前面的请求处理时间很长,后面就会有许多请求排队等着,这样就造成了“队头阻塞”的问题。

分块传输

对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。

HTTP2.0

因为http协议的庞大冗余,因此2.0不是新增特性,而是重新定义http协议。

在2.0版本中:

1.使用二进制数据传输。

2.支持主动推送资源。允许服务器未经请求,主动向客户端发送资源。

3.服务器进行长连接响应,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。

举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。

响应行

响应行:协议版本空格响应状态码空格状态码描述\r\n
在这里插入图片描述
响应状态码:直观的向客户反馈处理结果

HTTP状态码分类:
在这里插入图片描述
HTTP状态码列表:
在这里插入图片描述

头部

头部:关于请求或响应,或者正文的一些描述字段。

组成:key: value\r\n

典型头部字段:

  • Connection: 长短连接控制。keep-alive/close
  • Referer: 记录本次请求的来源链接
  • Content-Type: 用于表示正文的数据格式
  • Content-Length: 用于表示正文的长度,http解决粘包问题的关键字段
  • Location: 用于指定重定向的新链接地址,与3xx搭配使用

Cookie与Session

http协议是一种无状态的协议,浏览器对服务器的每一次请求都是独立的。为了使得页面能够产生一些动态信息,就需要保存”状态”,而cookie和session机制就是为了解决http协议无状态而产生。cookie是一种在客户端保存状态的方案,session是一种在服务器端保存状态的方案。

Cookie

  1. 一个客户端登录浏览器之后,服务端验证登录,成功之后,从服务器端发送的响应报文内头部字段Set-Cookie设置cookie信息(用户信息,状态等)返回给客户端。
  2. 客户端收到响应后,将Set-Cookie字段的cookie信息保存起来,下次请求服务器的时候从cookie文件中读取出cookie信息,通过请求报文内头部字段Cookie发送给服务器。

由于cookie中包含了一些敏感信息,虽然信息经过加密,但是如果被别人截获,那么只要把cookie向服务器提交,那么就可以冒充其他人访问服务器,存在安全隐患。所以就提出session解决此问题。

Session

session是服务端针对每个客户端所建立的会话,当客户端登录成功后,在服务端创建会话,在会话中记录客户端用户信息以及状态等,而只在客户端记录一个session id用于区分是哪个用户的session。

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含一个session id。如果有则表明已经为此客户端创建过session,服务器就按照这个session id查找出服务器端保存的session(查找失败的话,会创建一个新的session)。如果请求中不包含session id,则就回创建一个新的session,通过Set-Cookie字段将session id返回给客户端,客户端进行保存。

session需要在客户端存储一个session id。可以将这个值存储在Cookie,每次发送请求时通过Cookie请求头将其发送到服务器;也可以不使用Cookie,而将session id做为一个额外的请求参数,通过URL或请求体发送到服务器。

Cookie与Session的区别

Cookie是维护http通信状态的技术,将关键信息保存在客户端,每次请求服务器时,读取出来发送给服务端(存在安全隐患)。

Session是解决cookie安全隐患的技术,将关键信息保存在服务器,将session id发送给客户端,作为cookie保存起来,往后请求传输session id即可,解决了cookie泄密的风险。

总体来说Cookie与Session的区别:
(1)cookie数据存放在客户的浏览器上,session数据放在服务器上
(2)cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,如果主要考虑到安全应当使用session
(3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用cookie
(4)单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的cookie不能3K。
(5)所以:将登陆信息等重要信息存放为session;其他信息如果需要保留,可以放在cookie中

空行

空行:\r\n。是与头部最后一个字段的结尾\r\n组成连续的\r\n\r\n作为http头部结尾的标志。

正文

http是一个应用层协议,只是应用程序如何沟通的一种数据格式约定,在传输层是基于tcp协议实现的。

http客户端实际就是一个tcp客户端,http服务器实际上就是一个tcp服务器,只不过http客户端与服务端的通信使用的是http协议来约定数据格式而已。

简单的http服务器的搭建

服务器搭建流程:

1.搭建tcp服务端
2.获取新建连接
3.使用新建连接,等待接收数据(http协议的请求数据)
4.接收过程:先接收http头部,解析头部Content-Length确定正文长度
5.接收指定长度的正文
6.根据请求方法以及资源路径确定客户端的请求目的
7.进行具体对应的业务处理
8.组织http协议格式的响应数据,对客户端进行恢复
9.如果是短连接,则直接关闭套接字;如果是长连接,则继续等待接收数据

简单的http服务器代码:
tcp.hpp是Linux网络编程 | Socket编程:TCP服务器单执行流、多线程、多进程的实现中TCPSocket的封装

#include"tcp.hpp"
#include<sstream>

int main()
{
  TcpSocket lst_socket;
  //创建套接字
  CHECK(lst_socket.Socket());
  //绑定地址信息
  CHECK(lst_socket.Bind("192.168.134.141", 9000));
  //开始监听
  CHECK(lst_socket.Listen());
  while(1)
  {
    //获取新建连接
    TcpSocket newSocket;
    string ip;
    uint16_t port;
    bool ret = lst_socket.Accept(newSocket, &ip, &port);
    if(ret == false)
      continue;

    //接收数据
    string buf;
    ret = newSocket.Recv(buf);
    if(ret == false)
    {
      newSocket.Close();
      continue;
    }
    cout << "request:[" << buf  << "]\n"<< endl;

    buf.clear();
    //发送数据
    //组织数据格式
    stringstream ss;
    string body = "<html><body><h1>Hello World</h1></body></html>";
    ss << "HTTP/1.1 200 OK\r\n";
    ss << "Content-Length: " << body.size() << "\r\n";
    ss << "Content-Type: text/html;charset=UTF-8\r\n";
    ss << "Connection: close\r\n";
    ss << "Location: https://www.baidu.com\r\n";
    ss << "\r\n";
    ss << body;
    buf = ss.str();
    cout << "response:[" << buf << "]\n" << endl;
    ret = newSocket.Send(buf);
    if(ret == false)
    {
      newSocket.Close();
    }
  }
  //关闭套接字
  lst_socket.Close();
  return 0;
}

注意:

http服务器编写完毕之后:

  • 云服务器:记得设置安全组策略,开启对应端口
  • 虚拟机:记得关闭防火墙 sudo systemctl stop firewalld

示例:
在这里插入图片描述在这里插入图片描述

输入URL后发生了什么

  1. 浏览器向DNS服务器请求解析该URL中的域名对应的IP地址
  2. 解析出IP地址后,根据该IP地址和默认端口80,和服务器建立TCP连接
  3. 浏览器发出读取文件(URL中域名后面部分对应的文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
  4. 服务器对浏览器请求作出相应,并把对应的html文本发送给浏览器 释放TCP连接
  5. 浏览器解析HTML文本并局部渲染


这篇关于超详细的HTTP协议的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程