原创
最近更新: 2022/07/29 17:03

HTTP协议详解

HTTP即超文本传输协议(Hyper Text Transfer Protocol),工作在应用层,用于服务器与客户端之间的数据传输。

特点

  • HTTP协议简单,程序规模小,通信速度快,可伸缩性强,能够快速处理大量事务。
  • 工作方式:请求-响应模式。客户端先向服务器发送请求,然后服务器返回响应。
  • 无连接:每次连接只处理一个请求,服务器处理完客户请求并收到应答之后,即断开连接。
  • 无状态:协议不会保存以往的通讯状态,如果后续需要用到之前的信息就需要重传。为解决这一问题,出现了Cookie和Session技术。

报文结构

分为请求报文和响应报文。

请求报文

是客户端发送给服务器的报文,由请求行、请求头、请求体构成。

http请求报文结构

响应报文

是服务器返回给客户端的报文,由响应行、响应头、响应体构成。

http响应报文结构

报文首行

记录了识别报文类型最基本的信息。

请求方法

出现在在请求报文首行,标识请求的方法。

GET

  • 主要用于获取资源。一般情况下,直接输入的URL、点击连接跳转的URL所发送的都是POST请求。
  • 所有需要信息以键值对形式存放在url的参数部分,没有额外的负载部分(请求体)。

POST

  • 主要用于从客户端向服务器传输数据,数据一般存放在请求体中。

其他请求

设计初衷是用不同的方法来表示不同的语义,但是现在大多数请求都由GET和POST来完成,下面的方法几乎不再使用。

  • HEAD:与GET相似,但只获取报文首部
  • PUT:上传文件
  • DELETE:删除文件
  • TRACE:回显服务器收到的请求,主要用于测试或诊断
  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法
  • CONNECT:预留的方法,用于管道方式连接

如何构造一个POST请求

假设我们要向www.baidu.com发送一个POST,参数是a=1。

使用HTML构造form报文

其实就是在页面上添加一个表单和输入框。

//可以直接用HTML写一个,此处用JS构造
//构造form表单
var form = document.createElement("form")
form.action = "www.baidu.com"               //设置目标URL
form.mathod = "POST"                        //设置请求类型,form的mathod默认是POST
//构造数据,可构造多个数据
var input = document.createElement("input") //构造输入框,用来输入数据
input.name = "a"                            //参数名,对应键值对的key
input.value = 1                             //参数值,对应键值对的value
//连接和发送
form.appendChild(input)                     //将数据添加到表单
document.body.appendChild(form)             //将表单添加到页面
form.submit()                               //提交表单,发送POST请求

使用JavaScript发送Ajax构造POST请求

Ajax就是通过异步的JavaScript请求来加载和更新部分网页,就是用http请求来实现的。

//使用原生DOM
const xhr = new XHLHttpRequest()
xhr.open("POST", "www.baidu.com")
xhr.send("a=1&b=2")
//后面用来设置响应处理,此处省略

//使用JQuery
//第二个参数是一个js对象,用来存储发送的数据
//第三个参数是响应的处理函数,此处省略
$.post("www.baidu.com", {"a":1})

使用抓包工具

抓包工具可以提供更专业的网络包处理过程。常见的抓包工具有BurpSuite、fiddler、Charles等。详见各软件使用教程。

请求URL

出现在在请求报文首行,标识请求的URL。

http://host[:port]/path/filename[?query&key=value][#anchor]

  • http://表示使用http协议。
  • host表示访问的主机,可以是域名或者IP地址,例如www.baidu.com或127.0.0.1。
  • :port表示访问的端口,用来区分具体的应用。默认是80端口,即web应用。
  • /path/filename表示访问的路径,由目录和文件构成。该路径是虚拟路径,不一定对应现实的文件。默认是访问根目录/
  • ?query&key=value表示参数,以?开始,到#之前,一般以键值对形式出现。有多个参数的,用&分隔。也有用;分隔的。
  • #anchor表示锚,用于标识访问的网页的位置。默认从顶部访问。

协议版本

出现在报文首行,标识使用的http协议版本。

HTTP1.O

  • TCP连接不可复用,每次请求都要经过三次握手。提供了一个非标准字段Connection来提供长连接。
  • 只有GET、POST、HEAD三种请求。

HTTP1.1

  • 实现了长连接,TCP连接默认不关闭。
  • 允许多个请求同时发送,增加并发性。
  • 增加PUT、PATCH、OPTIONS、DELETE等请求方式。
  • 提供特殊的状态码和头部以支持身份认证机制。

HTTP2.0

详见计算机通信网络学习笔记-HTTP2.0

  • 增加双工模式,服务端可以同时处理多个请求,避免队列头部堵塞问题。
  • 服务器能够主动将一些资源推送到客户端,而无需等到客户端发出请求。
  • 在应用层与传输层之间加入了二进制分帧层,不再基于文本形式传输,提高了健壮性。
  • 支持使用gzip或compress进行报文头部压缩。同时双方维护一个头部信息表并标记索引号,这样双方通信时,头部只需要传输索引号即可。

响应状态码

  • 1xx 信息,服务器收到请求,需要请求者继续执行操作
    • 100 继续
  • 2xx 成功,操作被成功接收并处理
    • 200 OK
    • 201 已创建
    • 202 已接受,但尚未处理完成
  • 3xx 重定向,需要进一步的操作以完成请求
    • 301 Moved Permanently 永久移动。
    • 302 Moved temporarily 临时移动。
  • 4xx 客户端错误,请求包含语法错误或无法完成请求
    • 400 Bad Request 请求的语法错误
    • 401 Unauthorized 用户身份未认证
    • 403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
    • 404 Not Found 服务器无法根据客户端的请求找到资源(网页)
  • 5xx 服务器错误,服务器在处理请求的过程中发生了错误
    • 500 Internal Server Error 服务器内部错误,无法完成请求
    • 502 Bad Gateway 网关收到了无效的响应,可能是由于服务器负载过大导致的
    • 504 Gateway Time-out 远程服务器响应超时

报头

分为普通报头、请求报头、响应报头、主体报头。由许多的键值对构成,用于标识报文的属性。

本章介绍一些较为常见的报头,更多细节请访问此链接

普通报头

存在于请求或响应中,用于描述报文的通用属性,与主体中的信息无关。

Cache-Control 缓存控制

用于控制浏览器和服务器的缓存,多个控制标签用逗号分隔。

  • private:表示私有缓存,不与其他应用、用户或者代理服务器分享。
  • max-age=N:表示缓存持续N秒。与Expires相似,但是优先级更高。
  • no-store:表示不要缓存,用于内容经常变动的场景。
  • no-cache:表示可以缓存,但使用时要先去服务器验证是否过期。
  • must-revalidate:表示在max-age=N范围内,缓存可以使用,超过之后要去服务器验证是否过期。
  • ...

Date 日期:消息产生的时间

Connection 连接状态

用于控制连接是保持(keep-alive)还是关闭(close)。

  • HTTP1.0版本中默认是短连接(close)。
  • HTTP1.1版本后默认是长连接(keep-alive)。

请求报头

仅存在于请求报文当中,用于向服务器指定响应的类型。

Accept:用于指定客户端接收的数据类型,用逗号分隔(如gb2312)。不设置则表示接收任意数据类型。

Accept-Charset:用于指定客户端接收的字符集,用逗号分隔。不设置则表示接收任意字符集。

Accept-Encoding:用于指定客户端接收的编码(如gzip.deflate)。不设置则表示接收任意编码。

Accept-Language:用于指定客户端接收的自然语言(如zh-CN或en)。

User-Agent 用户代理

包含操作系统和浏览器的名称和版本,可用来根据浏览器版本设置返回页面的格式、识别爬虫等。但由于这个头可以随意修改,所以用处不太大。

if-Modified-Since:如果在此时间之后修改过,则请求资源。

if-None-Match:就是对应资源的Etag,用于服务器对比并决定是否更新cache。优先级高于if-Modified-Since

Cookie:由服务器生成,存储在客户端的数据,常常是认证信息、浏览记录等。

DNT:将该值设置为1表示拒绝网站的跟踪。

Host:表示目标服务器的地址和端口。

Referer:用于标识请求是从哪个网页发起的,可能用于审计、优化缓存或者防盗链。

Pragma:被Cache-Control代替。

响应报头

仅存在于响应报文中,用于描述服务器的信息或者指示客户端进行动作。

Location 定位:在响应报头中,当状态码为3XX(重定向)或201时有意义,用于记录重定向的网址。

Server 服务器:在响应报头中,包含服务器信息。

Last-Modified 上次修改:资源上一次修改的时间。

Etag 资源标签:相当于资源的版本号,当资源更新之后,会更新Etag,用于缓存更新时的对比。优先级高于Last-Modified

Set-Cookie:服务器向客户端发送的Cookie。

主体报头

用于描述主体/负载的信息。

Content-Type 数据类型

常见格式 application开头的多媒体格式 其他常见格式
text/html application/xhtml+xml 需要在表单中进行文件上传时使用的格式
text/plain application/xml multipart/form-data
text/xml application/atom+xml POST默认的数据类型
image/gif application/json application/x-www-form-urlencoded
image/jpeg application/pdf 任意类型二进制流
image/png application/msword application/octet-stream

Content-Encoding:用于描述主体的编码。

Content-Language:用于描述主体的自然语言。

Content-length 负载长度:主体的长度。

Expires 过期时间:主体中数据的过期时间,用于控制缓存。是HTTP1.0的产物,被Cache-Control替代。

Link

用于资源的预加载,和HTML的<link>标签相当。

格式:Link: <https://www.baidu.com>; param1=1, <https://www.google.com>; param2="2"

Cookie和Session

Cookie和Session机制是为了解决HTTP协议无法保存通信状态的问题而提出的。

Cookie

Cookie由服务器生成的文本内容,发送并存储在客户端中。此后每次客户端向服务器发送请求时都会带上Cookie,一般用于身份认证等。

分为持久Cookie和非持久Cookie,存储在硬盘或者内存中。

使用流程:

  1. 客户端首次向服务端发送请求。
  2. 服务器进行身份认证,生成Cookie并放在响应头的Set-Cookie中返回。
  3. 客户端收到服务器发来的Cookie,存储到本地。
  4. 客户端对该服务器后续的请求都会带上Cookie。
  5. 服务器对客户端发来Cookie进行解析,实现身份认证等功能。
  6. 如果Cookie过期或错误,则认证失败,客户端需要重新认证身份。

注意:

  • Cookie是明文传输的,如果不进行加密可能会导致信息泄露。
  • Cookie大小有限制,难以传输大量信息。

Session

Session是存储在服务器端的信息(往往是一个映射关系)。

Session机制往往与Cookie机制一同使用。服务器存储了有关客户端的信息,并生成一个JSESSIONID,通过Cookie发送给客户端。这样,HTTP可以通过传输Cookie来代替复杂的数据传输。

Session也可以脱离Cookie机制使用,即将JSESSIONID放在请求的URL中进行传输。

Session是针对会话的机制,存储在服务器内存中,当服务器端会话结束时,Session即过期。

评论区