HTTP协议入门指南

一、HTTP 协议

1.1 HTTP 是什么?

通俗来讲,它就是计算机通过网络进行通信的规则,是一个基于客户端请求与服务器端响应,无状态的基于TCP/IP协议传输数据的应用层(应用层可以理解为是由具体)协议。目前任何终端(手机,笔记本电脑。。)之间进行任何一种通信都必须按照HTTP协议进行,否则无法连接。

1.2 HTTP 是无状态的

HTTP 协议对于事务处理没有记忆能力,客户端第一次与服务器建立连接发送请求时需要进行一系列的安全认证匹配(三次握手)等。当客户端向服务器端发送请求,服务器端响应完毕后,两者断开连接,也不保存连接状态,一刀两断!恩断义绝!从此路人!下一次客户端向同样的服务器发送请求时,由于他们之前已经遗忘了彼此,所以每次都是建立一个全新的连接。

1.3 HTTP 是应用层的

应用层通俗来讲,就是并非是计算机底层写死的,而是各个应用根据协议规范而实现的;比如浏览器对HTTP的支持是由浏览器实现的;同时绝大多数编程语言也都内置或通过功能库实现了对HTTP协议的支持;当大家都遵循HTTP协议规范时,那么各自就能对应的识别及解析HTTP协议下的数据内容;

1.4 HTTP 是基于TCP/IP底层协议的

HTTP 使用TCP通信作为它的支撑运输协议(TCP是底层协议,是计算机底层实现,由应用层调用)。HTTP 客户机发起一个与服务器的 TCP 连接,一旦连接建立,浏览器(客户机)和服务器进程就可以通过套接字接口访问 TCP。

二、HTTP 请求报文

一个HTTP请求报文由请求行(request line)、请求头(request header)、空行和请求体(request body)4个部分组成。

下图给出了请求报文的规范格

v2-c920e11f00c2510d9a8fa4f4009d0f2e_720w.jpg

TTP请求报文就是一段规范格式的文本(文本,文本,文本,重要的说三遍);

所谓的发送JSON请求表单请求,并不是指发送的请求报文是JSON或表单,而是指将JSON或表单等格式的文本数据,放在请求报文的请求体中; 这些说法本质上是告知服务端的开发人员应当以什么样的方式来解析请求体内的数据; 切记:HTTP传输数据其本质就是传输符合上图格式的文本。

2.1 请求行

请求行分为三个部分:请求方法、请求地址和协议版本

2.1.1 请求方法

  • HTTP/1.1 定义的请求方法有8种:GETPOSTPUTDELETEPATCHHEADOPTIONSTRACE

  • 最常的有两种: GETPOST

  • 如果是 RESTful 接口的话一般会用到: GET(查)POST(改)DELETE(删)PUT(增)

2.1.2 请求地址

  • URL: 统一资源定位符,对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。

  • 互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它等。

  • 组成:<协议>://<主机>:<端口>/<路径>?<参数名>=<参数值>&<参数名>=<参数值>

  • 端口和路径有时可以省略(HTTP 默认缺省端口号是80)

v2-e48aaa3d17bc46cdf457795448666cda_720w.png

2.1.3 协议版本

  • 协议版本的格式为:HTTP/<主版本号>.<次版本号>,常用的有HTTP/1.0和HTTP/1.1

2.2 请求头

请求头为请求报文添加了一些附加信息,由键/值对组成,每行一对,名和值之间使用冒号分隔。

请求头的最后会有一个空行,表示请求头部结束,接下来为请求数据,这一行非常重要,必不可少。

常见请求头如下(更多详情可查看 Mozilla 官方说明):

请求头键名

请求头键值

说明

Host

127.0.0.1:8080

指明了客户端将请求发送到哪个服务器主机及哪个端口号

User-Agent

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62

让服务器端来识别发起请求的客户端软件的应用类型、操作系统、软件开发商以及版本号等

Accept

text/html,application/json

用来告知(服务器端)客户端可以处理的内容类型,这种内容类型用MIME 类型来表示。借助内容协商机制, 服务器可以从诸多备选项中选择一项进行应用,同时服务器端使用 Content-Type 应答头通知客户端它的选择。通常情况下如果客户端是浏览器,则浏览器会基于请求的上下文来为这个请求头设置合适的值,比如获取一个 CSS 层叠样式表时的值与获取图片、视频或脚本文件时的值是不同的。

Content-Type

application/json

告知服务器端,当前请求的请求体中数据的内容类型(基本MIME 类型表示),服务器端可以根据该类型对请求体中的数据进行解析;比如将 Json 格式的文本解析成字典或对象等。

Accept-Encoding

gzip,compress

客户端将自己能够理解的内容编码方式(通常是某种压缩算法)告知给服务端)。通过内容协商机制,服务端会选择一个客户端提议的方式进行响应,并在响应头 Content-Encoding 中通知客户端该选择。

Accept-Language

客户端告知服务器端它可以理解的自然语言,以及优先选择的区域方言。借助内容协商机制,服务器可以从诸多备选项中选择一项进行应用, 并使用 Content-Language 应答头通知客户端它的选择。浏览器一般会基于其用户界面语言自动为这个请求头设置合适的值。

Referer

http://localhost:8080/test/abc.html

告知服务器端,当前请求的来源地址,即表示当前请求是通过此来源里的链接进入的。服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等

Cookie

任意文本

其中包含先前由服务器通过 Set-Cookie 标头投放的或通过 JavaScript 的 Document.cookie 方法设置的,已经存储在客户端的 HTTP cookie

Connection

close/Keep-Alive

告知服务器端决定当前的事务完成后,是否关闭网络连接。如果该值是keep-alive,则网络连接就是持久的不会关闭,从而使得客户端对同一个服务器的请求可以继续在该连接上完成。

注意:浏览器一般会在发起请求时,默认自带一些请求头,一般包括HostUser-AgentAccept-LanguageConnection等。包括其他会发起HTTP请求客户端,也都会默认传输一些请求头(某些客户端如果开发者没有定义则传输默认的,如果定义了则传输开发者设定的值)。

3.3 请求体

请求体或者说请求数据是可选的部分,比如GET请求没有请求体。一般Json数据,表单数据都会放在请求体中进行传递。

下面是一个POST方法的请求报文:

POST  /index.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2  请求头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/
Content-Length:25
Content-Type:application/x-www-form-urlencoded

username=aa&password=1234

三、HTTP 响应报文

HTTP响应报文主要由状态行(response line)、响应头(response head)、空行以及响应正文(response body)4个部分组成。

下图给出了相应报文的规范格式:

v2-bdb035a8d48c2715f1fe485fbddb0d76.jpg

3.1 状态行

  • 由 3 部分组成,分别为:协议版本,状态码,状态码描述。

  • 其中协议版本与请求报文一致,状态码描述是对状态码的简单描述,所以这里就只介绍状态码。

3.2 状态码:

状态代码为3位数字。 1xx:指示信息--表示请求已接收,继续处理。 2xx:成功信息--表示请求已被成功接收、理解、接受。 3xx:重定向--要完成请求必须进行更进一步的操作。 4xx:客户端错误--请求有语法错误或请求无法实现。 5xx:服务器端错误--服务器未能实现合法的请求。

下面列举几个常见的:

状态码

说明

200

告知客户端请求已被成功响应处理

302

通知客户端进行跳转,跳转地址由响应头中Location属性指定。通常浏览器发出请求并在接受到该状态的响应后会自动跳转到Location指定的地址。

400

客户端请求有语法错误,服务器端不能正确识别;比如客户端发起一个请求体内容类型是Content-Type: application/json的请求,而实际在请求体中却放了非json格式的数据。服务器端根据协定进行解析json失败,这种情况下,就可以返回状态码 400。

403

服务器端接受到了请求,但拒绝提供相关服务(比如:普通会员访问只有管理员才有权限访问的功能页面)

404

客户端请求的资源不存在;如果是请求一个静态文件,说明服务器上对应地址不存在该文件; 如果是向一个动态服务器端(比如服务器端是Java,Python等构建的),说明客户端请求的对应路径服务器端没有与之匹配的功能;

500

服务器端接受到了请求,但服务器段出现内部错误。比如 Python 服务器端接受到了请求,但在连接数据库时,数据库访问失败;这种情况下可以返回状态码 500。

3.3 响应头

与请求头类似,为响应报文添加了一些附加信息;

常见响应头部如下:

响应头键名

说明

Server

服务器应用程序的名称和版本

Content-Type

响应正文的内容类型;浏览器一般通过该值来决定采用何种方式来处理,比如当值是text/html; charset=utf-8时,浏览器会尝试将响应正文以网页形式渲染呈现;而如果响应正文是HTML,Content-Type却是text/plain; charset=utf-8时,你猜的没错,你不会看到一个网页,而是会看到这个网页的源码文本。

Content-Length

响应正文长度。注意:这个正文长度通常不需要Python等服务器端进行设定,在使用Nginx,Apache时,这两货一般会自动计算出响应正文内容长度并响应给客户端。

Content-Encoding

响应正文使用的数据压缩格式

Content-Language

响应正文使用的自然语言

3.4 响应数据/响应正文

用于存放需要返回给客户端的数据信息。

下面是一个响应报文的实例:

HTTP/1.1 200 OK
Date: Sun, 17 Mar 2022 08:12:54 GMT
Server: Apache/2.2.8 (Win32) PHP/5.2.5
X-Powered-By: PHP/8.1.8
Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 4393
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8

<html><head><title>HTTP响应示例<title></head><body>Hello HTTP!</body></html>

注意:和 HTTP 请求报文一样,响应报文也是一段规范格式的文本,文本,文本(详见响应报文格式图); 所谓服务器端返回了 Json,其实际含义是,响应报文中正文的数据格式是一段Json文本。客户端工程师可以对响应正文进行 Json 解析。

四、一切都是文本

HTTP 报文综上所述就是一个被约定了格式的文本;不存在Json, 整数,浮点数这些编程语言中的语法概念;

无论客户端或服务器端,在对应的编程中进行处理时获取的请求头,请求数据,响应头,响应数据等,虽然看上去你直接获取到了请求头字典,Json字典;甚至你还特意去判断这些内容的数据类型,并且的确不是文本;这可能让你很迷惑,HTTP 报文不是说全部是文本吗?

原因是:由于HTTP 报文格式是约定俗称的标准,进而绝大多数编程语言及基础 HTTP 功能库已经实现了HTTP 报文的格式解析,甚至会自动识别Content-Type,并根据格式类型解析成对应编程语言内的数据类型,而不是让你再去解析一遍(编程,编程,永远是让重复的事情不用重复的做)。

所以,你在使用时,是基于对应语言,工具或功能库解析后进行HTTP相关操作。 而不是直接处理原始 HTTP 报文。