一、引言
在现代互联网的广阔世界中,HTTP 协议无疑是支撑整个网络生态系统的基石之一。每当我们打开浏览器访问一个网站,发送一条社交媒体消息,或者进行一次在线购物时,HTTP协议都在默默地为我们传输数据。尽管 HTTP 协议在我们的日常生活中无处不在,但许多人对它的内部工作原理知之甚少。
HTTP(HyperText Transfer Protocol,超文本传输协议)是用于分布式、协作和超媒体信息系统的应用层协议。它的主要功能是定义客户端(例如浏览器)和服务器之间如何请求和传输数据。自1991年首次发布以来,HTTP 协议经历了多个版本的演进,从最初的简单文本传输到如今的高效二进制传输,每一次的改进都带来了显著的性能提升和安全增强。
本篇博客旨在深入解析HTTP协议的各个方面。我们将从 HTTP 协议的基本特点开始,探讨它的工作原理和报文结构,详细介绍常用的 HTTP 方法和状态码,以及 Cookie 和 Session 在状态管理中的应用。随后,我们还将比较 HTTP 和 HTTPS 的区别,并回顾HTTP协议的发展历程。通过这篇详尽的讲解,希望能帮助读者全面理解HTTP协议,为今后的网络应用开发提供坚实的理论基础。
二、HTTP 请求
大家先来看一段 HTTP 协议的报文格式,这里要使用 "Fiddler" 这个抓包工具。打开一个网页,涉及到多次浏览器和服务器之间的交互,首先看一下浏览器给服务器的请求,如下:
一般来说,浏览器对服务器请求是不涉及到 body 的,一般是服务器对浏览器的响应才会有 body(不绝对,只是这样建议,类似于代码风格,但是要是想写也没错)。
2.1、首行
首先来了解一下首行的结构:
首行的结构一般是 [方法] + [url] + [HTTP 协议版本]
2.1.1、方法
这里的方法和 Java 中的方法差不多,如上图的 GET,一般是发送请求给服务器的时候才使用的,还有其他的方法,如下:
方法 | 说明 | 支持的 HTTP 协议版本 |
GET | 获取资源(可理解为发送给服务器的请求) | 1.0、1.1 |
POST | 传输实体主体(可理解为服务器返回的响应) | 1.0、1.1 |
PUT | 传输文件 | 1.0、1.1 |
HEAD | 获取报文首部 | 1.0、1.1 |
DELETE | 删除文件 | 1.0、1.1 |
OPTIONS | 询问支持的方法 | 1.1 |
TRACE | 追踪路径 | 1.1 |
CONNECT | 要求用隧道协议连接代理 | 1.1 |
LINK | 建立和资源之间的联系 | 1.0 |
UNLINE | 断开连接关系 | 1.0 |
(重点★)GET 和 POST 的区别
首先盖棺定论:GET 和 POST 没有任何区别!!!!! 你可以使用任何一个发送请求或者接受请求,只是使用建议上有区别,注意,只是建议,相当于你还是想怎么用都可以,但是建议你这么做:GET 发送请求,POST 接收响应。
还是建议:从使用习惯上来说,GET 的数据通常是把数据放到 query string 中的,POST 通常是把数据放到 body 中的,关于 query string 和 body 是什么,本篇博客都会介绍。
2.1.2、URL
URL(统一资源定位符)是用于定位互联网上资源的标准格式。一个典型的 URL 包含以下几个部分:
scheme://username:password@hostname:port/path?query string#fragment
各部位解析
- scheme(协议方案名):
- 表示使用的协议,如
http
、https
、ftp
等。 - 示例:
http://
- username:Password(可选, 现在一般没有了):
- 用于身份验证的用户名和密码。
- 示例:
user:pass@
- hostname(服务器地址):
- 服务器的域名或 IP 地址。(可以是外网 ip [本身就是唯一的],可以是内网 ip [访问局域网中的设备],也可以是环回 ip [访问自己])
- 示例:
www.example.com
- port(服务器端口号,可选,一般来说会省略,因为很多知名端口号都会设定默认值):
- 服务器的端口号,默认为
80
(HTTP)或443
(HTTPS)。 - 示例:
:8080
- path(带层次的路径,也可以省略,省略的话相当于访问根目录):
- 指向特定资源的路径。
- 示例:
/path/to/resource
- query string(查询参数,可选,有和没有都可让后端代码根据情况处理):
- 以
?
开头,&
分隔的键值对,用于传递额外参数。 - 示例:
?key1=value1&key2=value2
- Fragment(片段,可选,也不太常见,一般是文档类网站能看到):
- 以
#
开头的部分,通常用于指向文档中的某个位置。 - 示例:
#section1
示例 URL
https://user:pass@www.example.com:8080/path/to/resource?key1=value1&key2=value2#section1
这个示例包含了 URL 的各个部分,可以帮助理解 URL 的基本结构和用法。
2.1.3、版本号
这个没什么好说的,就是 HTTP 协议的版本号,现在比较主流的就是两个,一个 1.0 另一个 1.1。
2.2、请求头(header)
header 的整体的格式也是 "键值对" 结构。每个键值对占一行,键和值之间使用分号分割。报头的种类有很多,此处仅介绍几个常见的。
2.2.1、Host
表示服务器主机的地址和端口,就是这玩意儿
但是这大家是不是发现很眼熟?这在首行的 URL 不是已经有了吗?为什么还要再写一遍呢?其实也是有有例外的,比如说使用了代理,可就不一定一样了哈。
2.2.2、Content-Length
描述了 body 有多长,body 开头我们都知道,是空行开头的,但是是到哪里结束呢?这个就得看我们的 Content-Length 了,它说 body 是多长那就是多长,这个就是为了解决我们的粘包问题嘛,不然不好区分。
2.2.3、Content-Type
这个主要是描述 body 是什么类型的数据,在请求中,常见的类型有:
- application/x-www-form-urlencoded
- multipart.form-data
- application/json(很常用)
不清楚什么是数据类型的可以看我上一篇博客《HTTP 协议,Content-Type 格式介绍篇》
2.2.4、User-Agent(简称 UA)
这个主要是给服务器说明当前机器的系统和浏览器的版本,至于这个有什么用呢?其实在互联网发展的早期,网站主要就是文字(早期的网站,相当于就是把报纸、杂志这样的传统媒体搬到了电脑上),但是如果说你的一个电脑的系统很低就带不动版本号比较新的浏览器,浏览器比较旧的话对于图片、js(交互)、播放视频/音频等功能就不支持,因此想了个办法,浏览器在发起 HTTP 请求的时候,先向服务器自报家门,告诉服务器我是用啥系统,啥浏览器上网的,服务器就可以根据这个情况,分别进行对待。
然而现在,各大浏览器支持的功能都非常丰富,而且比较完善,不会涉及到很大的更新,这时候 UA 的意义就笑了很多,UA 现在主要是用来区分 移动端 还是 PC端 的。
2.2.5、Rederer
这个是描述了当前的页面从哪里来的,如果说是通过浏览器地址直接输入 url 或者是点击收藏夹打开的网页,这个请求时不带有 referer 的,但是如果你是点击了某个网页的内容产生了挑战,此时就是带有 referer 的。
2.2.6、Cookie
这是浏览器本地存储数据的一种机制,在浏览器访问服务器的时候,此时浏览器对于服务器来说时一无所知的,因为浏览器上时没有任何关于服务器的相关数据的,所以,此时浏览器就需要保存一些用户的数据,保存的这些数据呢就是放到 Cookie 中,这个数据可以是临时性,临时性的数据就是放到客户端/浏览器这边保存(电脑换了也就没了),也可以是放在服务器上保存的(换了电脑也有效),那临时性的数据有那些呢?比如说我们登录一个博客吧,这就是临时性的,永久性的就比如说我写的这个博客的草稿,只要登录我这个账号,就能通过草稿箱找到我写的草稿,那肯定会有疑问了,为什么临时性的数据不直接保存到文件中呢?很显然,这样是肯定行不通的,因为有个东西叫电脑病毒,如果说浏览器网页能直接操控你的磁盘文件,那多可怕?一不小心点进一些不正规的网站,这些家伙就来了。
那这个主要有什么用呢?其实这个可以存储你的身份信息,然后发送给服务器,服务器再通过这个信息,结合 Session,来查询你保存的一些操作呀信息呀什么的有哪些,这里简单介绍一个 Session,这个是和 Cookie 来联合使用的,大家还记得 Map
吧?这里的 Cookie 就相当于是 key
,而 Session 就相当于是 value
。
现在针对 Cookie 进行一个简单的总结:
1.Cookie 从哪里来?
Cookie 是从服务器返回给浏览器的。
2.Cookie 保存在哪里?
Cookie 保存在浏览器上,浏览器所在电脑的硬盘上,每个域名都有自己的一组 Cookie(方便区分)。
3.Cookie 里的内容是啥?
Cookie 中的内容是键值对结构的数据,这里的键值对都是程序猿自定义的.其中往往会有一个键值对,作为用户的身份标识(不同网站身份标识的 key
和 value
可能都是不同的)。
4.Cookie 的内容到哪里去?
后续再访问这个网站中的各个页面,就都会在请求中带上 Cookie,服务器就可以进一步的知道客户端的详细情况了。
2.3、空行
这个没什么好介绍的吧,故名思意,空行就是什么都没有,用来分隔 Header 和 body 的。
2.4、正文(body)
一般来说正文是响应才有的,但是不绝对,程序猿可以自己定义,请求正文的格式可以多种多样,具体取决于 Content-Type
头部字段的值。常见的格式包括:
- application/x-www-form-urlencoded:键值对格式,常用于表单提交。数据在 URL 编码后被放入请求正文中。
- multipart/form-data:多部分格式,常用于文件上传。每部分包含一个文件或表单字段。
- application/json:JSON 格式,用于传递结构化数据。
- text/plain:纯文本格式,传递文本数据。
- application/xml:XML 格式,用于传递结构化数据。
三、HTTP 响应
这里响应的格式也和请求差不多,如下:
3.1、首行
响应首行和请求的首行还是有点区别的哈,版本号这个就不过多的解释了,主要介绍一下状态码是啥意思。
状态码就是服务器返回这次响应的定性,例如成功啊,失败啊,或者其他情况,如下,大家做个简单的了解即可,不需要全记住。
状态码 | 分类 | 描述 |
1xx 信息性状态码 | ||
100 | Continue | 客户端应继续其请求。 |
101 | Switching Protocols | 服务器已经理解了客户端的请求,并将通过不同的协议来完成请求。 |
102 | Processing | 服务器已经收到并正在处理请求,但尚未完成响应。 |
103 | Early Hints | 预提示,主要用于提示客户端准备资源链接。 |
2xx 成功状态码 | ||
200 | OK | 请求成功,服务器已成功处理了请求。 |
201 | Created | 请求成功,并且服务器创建了一个新的资源。 |
202 | Accepted | 服务器已接受请求,但尚未处理。 |
203 | Non-Authoritative Information | 请求成功,但返回的信息不是来自服务器的原始资源。 |
204 | No Content | 服务器成功处理了请求,但没有返回任何内容。 |
205 | Reset Content | 服务器成功处理了请求,要求客户端重置文档视图。 |
206 | Partial Content | 服务器成功处理了部分GET请求。 |
207 | Multi-Status | 之后的消息体将是一个XML消息,解释多个资源的不同状态。 |
208 | Already Reported | DAV绑定成员的状态已经在之前的多状态响应中被枚举。 |
226 | IM Used | 服务器已经满足了GET请求,响应是一个代表当前实例的结果。 |
3xx 重定向状态码 | ||
300 | Multiple Choices | 请求有多个可能的响应,客户端应选择其中一个。 |
301 | Moved Permanently | 请求的资源已永久移动到新位置。 |
302 | Found | 请求的资源临时从不同的URI响应。 |
303 | See Other | 对应当前请求的响应可以在另一个URI上找到。 |
304 | Not Modified | 请求的资源未修改,可以使用缓存版本。 |
305 | Use Proxy | 请求的资源必须通过代理访问。 |
307 | Temporary Redirect | 请求的资源临时从不同的URI响应。 |
308 | Permanent Redirect | 请求的资源已永久移动到新位置。 |
4xx 客户端错误状态码 | ||
400 | Bad Request | 服务器无法理解请求的格式。 |
401 | Unauthorized | 请求需要用户验证。 |
402 | Payment Required | 保留状态码,将来可能会使用。 |
403 | Forbidden | 服务器理解请求,但拒绝执行。 |
404 | Not Found | 请求的资源未找到。 |
405 | Method Not Allowed | 请求的方法不被允许。 |
406 | Not Acceptable | 请求的资源不满足请求的内容特性。 |
407 | Proxy Authentication Required | 请求需要代理身份验证。 |
408 | Request Timeout | 服务器等待请求超时。 |
409 | Conflict | 请求因冲突无法处理。 |
410 | Gone | 请求的资源已永久删除。 |
411 | Length Required | 请求缺少Content-Length头。 |
412 | Precondition Failed | 请求头的某些条件在服务器上测试失败。 |
413 | Payload Too Large | 请求体积太大,服务器无法处理。 |
414 | URI Too Long | 请求的URI过长,服务器无法处理。 |
415 | Unsupported Media Type | 请求的媒体类型不被支持。 |
416 | Range Not Satisfiable | 请求的范围无法满足。 |
417 | Expectation Failed | 服务器无法满足Expect请求头字段的要求。 |
418 | I'm a teapot | 服务器拒绝冲泡咖啡,因为它是一个茶壶(愚人节笑话)。 |
421 | Misdirected Request | 请求被定向到一个无法生成响应的服务器。 |
422 | Unprocessable Entity | 请求格式正确,但由于语义错误无法处理。 |
423 | Locked | 请求的资源被锁定。 |
424 | Failed Dependency | 由于之前的请求失败,当前请求失败。 |
425 | Too Early | 服务器拒绝处理早期请求。 |
426 | Upgrade Required | 客户端应切换到TLS/1.0。 |
428 | Precondition Required | 请求需要先决条件。 |
429 | Too Many Requests | 客户端发送的请求次数过多。 |
431 | Request Header Fields Too Large | 请求头字段太大,服务器无法处理。 |
451 | Unavailable For Legal Reasons | 请求的资源因法律原因不可用。 |
5xx 服务器错误状态码 | ||
500 | Internal Server Error | 服务器内部错误。 |
501 | Not Implemented | 服务器不支持请求的方法。 |
502 | Bad Gateway | 服务器作为网关或代理,从上游服务器收到无效响应。 |
503 | Service Unavailable | 服务器暂时不可用。 |
504 | Gateway Timeout | 服务器作为网关或代理,未及时从上游服务器收到响应。 |
505 | HTTP Version Not Supported | 服务器不支持请求的HTTP版本。 |
506 | Variant Also Negotiates | 服务器内部配置错误。 |
507 | Insufficient Storage | 服务器无法存储完成请求所需的内容。 |
508 | Loop Detected | 服务器检测到无限循环。 |
510 | Not Extended | 请求需要进一步扩展。 |
511 | Network Authentication Required | 需要进行网络身份验证。 |
这个表格列出了常见的HTTP状态码分类和描述,涵盖了所有1xx、2xx、3xx、4xx和5xx类别的状态码。
这里挑几个比较常见的总结一下:
200 成功。
404 访问的资源不存在
403 访问的资源没有权限
502 服务器挂了
504 服务器响应超时了(多半也是挂了)
302 重定向(浏览器会自动跳转到其他的页面)
3.2、请求头
这个也没什么好说的,HTTP 请求中已经介绍了。
3.3、正文(body)
其实响应的正文可以看成是服务器返回给客户端的一个页面,然后正文就是通过代码的方式,来描述这个页面的,正文通常是以原始数据、HTML、JSON、XML等形式编码的内容。
常见的响应正文格式包括:
- text/html:HTML 格式,浏览器可以直接显示。
- application/json:JSON 格式,适用于 API 响应,客户端通常会解析并使用数据。
- application/xml:XML 格式,适用于 API 响应,类似于 JSON。
- text/plain:纯文本格式。
- image/jpeg, image/png 等:二进制图像数据。
四、总结
通过对 HTTP 协议的深入解析,我们全面了解了 HTTP 协议的各个方面,包括其基本特点、工作原理和报文结构。我们探讨了 HTTP 请求的组成部分,如首行、请求头、空行和正文,以及不同 HTTP 方法的作用和状态码的分类。特别是,通过对 GET 和 POST 方法的详细对比,我们明白了虽然这两者在使用建议上有所不同,但在功能上是没有本质区别的。
此外,我们还介绍了 HTTP 响应的组成部分和常见的状态码,了解了服务器如何通过不同的状态码向客户端传递处理结果的信息。通过这些内容,我们不仅掌握了 HTTP 协议的基本知识,还具备了分析和处理 HTTP 请求和响应的能力。
最后,Cookie 和 Session 的介绍使我们对HTTP状态管理有了更深入的认识,理解了如何在无状态的 HTTP 协议中实现用户会话的管理。这些知识对于理解和开发基于网络的应用系统有着重要的帮助。
五、结语
HTTP 协议作为互联网的基础协议,贯穿于我们日常的网络交互中。通过本篇博客的详细讲解,我们不仅了解了 HTTP 协议的基本工作原理和结构,还掌握了常见的 HTTP 方法和状态码的使用方法。希望通过这篇博客,能够帮助读者更好地理解和运用 HTTP 协议,为今后的网络应用开发提供坚实的理论基础。
在未来的网络开发中,我们不仅要深入理解 HTTP 协议的各个方面,还需要关注协议的安全性和性能优化,不断提升我们的技术水平。无论是构建简单的网页应用,还是开发复杂的分布式系统,HTTP 协议的知识都是我们必备的技能之一。希望大家在今后的学习和工作中,能够灵活运用所学知识,打造更加高效、安全的网络应用。