HTTP是什么,哪些地方使用了HTTP呢?
我们使用计算机时,最常用的其实就是输入一个网址,例如www.baidu.com,然后就跳转到百度搜索的界面了。那么为什么我们输入的是一个网址,呈现出的却是一个web界面呢,这就得益于http协议了,Web 界面不会凭空出来,根据 Web 浏览器地址栏中指定的 URL,Web 使用一种名为 HTTP 的协议作为规范,完成从客户端到服务端的一些流程。可以说,Web 是建立在 HTTP 协议上进行通信的
HTTP是什么?
HTTP:超文本传输协议,是互联网使用最为广泛的一种协议,所有万维网(WWW)文件都必须遵守这个协议.HTTP和TCP/IP协议簇中的众多协议一样,用于客户端和服务器端的通信
什么是超文本?
HTTP传输的内容就是超文本
- 先来说一下文本:互联网早期的时候只是简单的字符文字,但随着技术发展,文本的涵义已经扩展成了图片,视频,压缩包等,这些在HTTP眼里都是文本!
- 再来说超文本:超文本就是超越了普通文本的文本,它是文字,图片,视频的混合体。最关键有超链接,能从一个超文本跳转到另一个超文本
HTML就是最常见的超文本,HTML本身是纯文字文件,但是内部使用了很多标签去定义图片、视频、压缩包,经过浏览器的解析,呈现出来的就是一个有文字、画面的网页了
HTTP有几个版本?
其实我们现在使用的HTTP协议是20几年前的版本,也就是说作为web文档传输协议的HTTP已经很长时间没有更新了
HTTP/0.9——HTTP于1990年问世,仅支持GET请求方式,并且只可以访问HTML格式的资源,那时候的HTTP并没有作为正式的标准被确立
HTTP/1.0——1996年5月HTTP作为正是标准被公布,相比0.9,1.0版本新增了POST、HEAD请求方式;并且不再局限于HTML格式,根据content-type可以支持多种数据格式,1.0版本的工作方式是短连接(传输一次资源就要建立连接一次)
HTTP/1.1——1997年公布,是目前最主流的HTTP版本,虽然当年HTTP协议是为了解决文本传输的困难,但是现在早已经超出了web这个框架的限制。但是1.1版本最大的变化还是引入了流水线机制和长连接(一次连接即可)
区分URL和URI
URL相信大家都很熟悉,就是我们在浏览器输入的网址,URL全称uniform resource location,统一资源定位符,举个例子——https://baidu.com
URI是uniform resource identifier的缩写,全称统一资源标识符,URI的三个单词的定义为
- Uniform:统一规定的格式可方便处理多种不同类型的资源
- Resource:资源的定义是可标识的任何东西。不仅可以是单一的,也可以是一个集合
- Identifier:标识可标识的对象。也称为标识符
综上,URI就是某个协议方法表示的资源的定位标识符,比如说,采用HTTP协议时,协议方案就是http,除此之外还有ftp、Telnet等,标准URI协议方法有30余种
URI有两种格式
1.相对URI——指从浏览器中基本URI处指定的URL,比如/user/1.jpg
2.绝对URI——使用涵盖时的全部信息
总结:URI用字符串标识互联网的某处资源,而URL是标识资源的地点,所有url可以看出URI的子集
HTTP请求与响应
在浏览器中输入网址访问某个网站时,浏览器(客户端)会将你的请求封装成HTTP请求传输给服务器站点,服务器收到请求后会组织响应数据封装成一个HTTP响应返回给浏览器,所以HTTP请求一定是从客户端发起的,换句话说,肯定是从客户端开始建立通信的
什么是HTTP请求报文
HTTP请求报文包含3个部分
- 请求行——必须在请求报文的 第一行
- 请求头(主体)——从第二行开始,到第一个空行结束
- 请求体(通常以键值对{key:value}传输数据)——和请求头之间存在一个空行
请求行开头的POST表示访问服务器的类型,也叫作方法。随后的/form/login是要访问的资源对象,也叫作请求URI,最后的就是HTTP协议版本号,用来提示服务器客户端使用的HTTP版本
这个HTTP请求的意思就是:请求访问某台HTTP服务器上的/form/login处的页面资源,并附带参数name=veal,age=37
注意,无论是 HTTP 请求报文还是 HTTP 响应报文,请求头/响应头和请求体/响应体之间都会有一个空行,且请求体/响应体并不是必须的。
HTTP请求方法
常见的HTTP方法有:GET,POST,HEAD,PUT,DELETE,OPTIONS,CONNECT,TRACE,但是较常用的就前面4个
1.GET获取资源
GET方法用来请求访问被URI识别的资源。指定的资源经服务器端解析后返回响应内容
使用GET请求的例子
2.POST传输实体数据
POST主要就是用来传输数据,GET是用来获取某个资源(和名字很符合)
3.PUT传输文件
PUT方法用来传输文件,由于其自身不带验证机制,任何人都可以上传 ,所以存在安全性问题,一般不使用
4.HEAD获取报文首部
和GET方法类似,但是不返回报文主体部分,主要就是用于确认URI的有效性以及资源的更新日期
5.DELETE删除文件
和PUT相反,用来删除文件,并且同样是不安全的(HTTP就是不保证安全的),按照请求的指定URI删除资源
6.OPTIONS查询支持的方法
用于获取当前URI所支持的方法,若请求成功,会在HTTP响应头中包含一个名为Allow的字段,值是所支持的方法,如“GET,POST”
HTTP请求头
请求头就是用来补充的附加信息、客户端信息、对响应内容的优先级等等,常见的请求头有
1.Referer——表示这个请求是从哪个 URI 跳过来的。比如说通过百度来搜索淘宝网,那么在进入淘宝网的请求报文中,Referer 的值就是:www.baidu.com。如果是直接访问就不会有这个头。这个字段通常用于防盗链。
2.Accept——告诉服务端所支持的响应数据类型(对应的响应报文也会有一个对应的content-type表示返回的数据类型,如果这两个不一致,就会报错)
上图中的
text/plain;q = 0.3
表示对于text/plain
媒体类型的数据优先级/权重为 0.3(q 的范围 0 ~ 1)。不指定权重的,默认为 1.0。
常见的数据格式类型:
3、Host:告知服务器请求的资源所处的互联网主机和端口名,这个字段是HTTP1.1版本中唯一要求必须要包含在请求头中的字段(告诉服务器要去哪里找资源给我)
4.Cookie:客户端的cookie就是通过这个报文传给服务器的
Cookie: JSESSIONID=15982C27F7507C7FDAF0F97161F634B5
5.Connection:表示客户与服务端的连接类型(keep-alive表示长连接,close是以关闭)
6.Content-length:请求体的长度
7.Accept-Language:浏览器告知服务器自己支持的语言
8.Range:对于只需获取部分资源的范围请求,包含首部字段 Range 即可告知服务器资源的指定范围
HTTP响应报文(和请求报文一样三部分)
- 响应行(必须在 HTTP 响应报文的第一行)
- 响应头(从第二行开始,到第一个空行结束。响应头和响应体之间存在一个空行)
- 响应体
在响应行开头的HTTP1.1表示版本,200是状态码,OK是原因短语
HTTP状态码(重要)
HTTP状态码负责表示客户端HTTP请求的返回结果,标记服务器端处理是否正常、通知出现的错误等工作
状态码是三位数,第一个数字决定响应的类别
2xx:请求正常处理完毕
200 OK:客户端请求成功
204 No Content:无内容,服务端成功处理,但无内容返回。一般用在客户端给服务器发送信息,服务器不用返回数据的情况
![]()
206 Partial Content:服务器已经完成了部分GET请求(客户端进行了范围请求),响应报文中包含Conten-Range指定范围的实体内容
![]()
3xx:需要进行附加操作以完成请求(重定向)
301 Moved Permanently:永久重定向,表示请求的资源已经永久的移动到了别的位置
302 Not Found:临时重定向,表示请求的资源临时搬到了别的位置
303 See Other:也是临时重定向,应使用GET定向获取请求资源,303功能和302一样,区别在于303要求客户端用GET请求访问
304 Not Modified:表示客户端发送附带条件的请求(GET方法请求报文中的IF...)时,条件不满足。返回304时,不包含任何响应实体,虽然304是3xx,但是和重定向无关系
307 Temporary Redirect:临时重定向,和302一样,POST不会变成GET
4xx:客户端错误
400 Bad Request:客户端请求有语法错误、服务器无法理解
401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authentic报头域一起使用
403 Forbidden:服务器收到请求,但是拒绝提供服务
404 Not Found:请求资源不在,比如输入了错误的URL
415 Unsupported media type:不支持的媒体类型
5xx:服务器端错误、服务器未能实现合法的请求
500 Internal Server Error:服务器发生不可预期的错误
503 Server Unavailable:服务器当前处于超负载或者停机维护了,暂时不可以处理客户端请求,一段时间后可以恢复正常
HTTP响应头
响应头也是用键值对{k:v}用于补充响应的附加信息,服务器信息和客户端的附加要求等
这里的Location字段,可以将响应接收方引导至某个URI位置不同的资源,通常来说配合3xx状态码使用,告知客户端需要重定向。
HTTP的连接方式
1.短连接(非持久)
在HTTP/1.0中,客户端和服务端每进行一次HTTP会话,就建立一次连接,任务结束就断开。当客户端浏览器访问的某个HTML或其他类型web页中包含其他的web资源(JavaScript文件,图像,CSS等),每遇到一个这样的资源,浏览器就重新建立一个HTTP会话。这种方式称为短连接
那么每次HTTP请求都要建立一次连接,由于HTTP是基于TCP/IP协议,那每次连接都要经历
TCP三次握手-TCP四次挥手的开销。
这种方式是存在很大的弊端的,假设访问一个含有很大图片的HTML页面,每请求一张图片就建立一次连接,造成无所谓的TCP连接或断开,大大增加了通信量的开销
2.长连接(持久连接)
从HTTP/1.1开始,默认使用长连接(keep-alive),使用长连接的HTTP协议,会在响应头加入Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive 不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如 Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP的长连接短连接实质就是TCP协议的长连接和短连接
3.流水线(管线化)
默认情况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。
持久连接使得多数请求以流水线(管线化 pipeline)方式发送成为可能,即在同一条持久连接上连续发出请求,而不用等待响应返回后再发送,这样就可以做到同时并行发送多个请求,而不需要一个接一个地等待响应了。(像队列一样)
无状态的HTTP
HTTP是无状态的协议,也就是说它不对之前发生过的请求和响应状态进行管理,即无法根据之前的状态进行本次请求的处理
这样就会出现一个问题,如果HTTP无法记住用户的登录状态,那每次页面的跳转都会导致用户需要重新登录一次。(当然无状态也有其优点,因为无需保存状态,所以CPU和内存消耗较少,而且简单,所以应用广泛)
在保留无状态协议特征的同时,又要解决其带来的问题,方案很多种,最常用简单的就是Cookie
Cookie通过在请求和响应报文中写入Cookie信息来控制客户端状态,具体的说,Cookie会根据从服务器端发送的响应报文中的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往服务器发送请求时,客户端自动在请求报文中加入Cookie值发送,服务器收到客户端发送过来的Cookie后,会检查是哪一个客户端发来的连接请求,然后对比服务器上的记录,得到之前的客户端状态信息
通俗的说,客户端和服务器第一次建立连接时,服务器会给客户端发送一个装有客户端状态信息的身份证(Cookie),后续客户端请求服务器的时候带上身份证(Cookie),服务器就认得了
1.没有运用Cookie的请求(第一次建立连接)
对应的请求报文
GET /reader/ HTTP/1.1
Host: baidu.com
* 首部字段没有 Cookie 的相关信息
响应报文
HTTP/1.1 200 OK
Date: Thu, 12 Jul 2020 15:12:20 GMT
Server: Apache
<Set-Cookie: sid=1342077140226; path=/; expires=Wed, 10-Oct-12 15:12:20 GMT>
Content-Type: text/plain; charset=UTF-8
2.第2次之后的请求(带有Cookie)
对应的请求报文
GET /image/ HTTP/1.1
Host: baidu.com
Cookie: sid=1342077140226
HTTP断点续传
所谓断点续传指的就是下载传输文件可以中断,之后重新下载时可以接着中断的地方开始下载,而不必从头开始下载。断点续传需要客户端和服务器都支持
这个功能的实现并不困难,原理其实就是HTTP请求头字段中的Range字段和响应头的
Content-Range字段,客户端一块一块的请求数据,最后将下载好的数据块拼接成完整的数据。打个比方,浏览器请求服务器上的一块服务,所发出的请求如下
设域名为www.baidu.com,文件名为down.zip
GET /down.zip HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-
excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Connection: Keep-Alive
服务器收到请求之后,按要求寻找文件,提取文件信息,然后返回给浏览器,响应信息为
200
Content-Length=106786028
Accept-Ranges=bytes
Date=Mon, 30 Apr 2001 12:56:11 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT
那如果要实现断点续传,客户端应该在发送请求报文时加多一条信息——从何处开始请求数据,比如要求从2000070字节开始
GET /down.zip HTTP/1.0
User-Agent: NetFox
RANGE: bytes=2000070-
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
其中的RANGE:bytes=2000070-就是表面down.zip这个文件从2000070开始下载,之前的不用传输
服务器收到该信息后,返回信息为
206
Content-Length=106786028
Content-Range=bytes 2000070-106786027/106786028
Date=Mon, 30 Apr 2001 12:55:20 GMT
ETag=W/"02ca57e173c11:95b"
Content-Type=application/octet-stream
Server=Microsoft-IIS/5.0
Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT
响应报文也多了一行——Content-Range,返回的代码也是206而不是200了,代表部分完成了客户端的GET请求。
HTTP的缺点
- 通信使用明文(不加密),内容可能被窃听
- 不验证通信对方的身份,因此有可能遭遇伪装
- 无法证明报文的完整性,所以有可能被篡改
这些问题不仅在 HTTP 上出现,其他未加密的协议中也存在类似问题,为了解决 HTTP 的痛点,HTTPS 应用而生,说白了 HTTP + 加密 + 认证 + 完整性保护就是 HTTPS 协议