HTTP 叫做:超文本传输协议(Hyper Text TransferProtocol,HTTP)是一个简单的请求-响应协议,它通常运行在 TCP/IP 五层协议栈的应用层。是一种非常广泛的应用层协议(客户端和服务器建立连接在应用层)。
1. HTTP 工作过程
如果用户操作作为一个客户端,使用浏览器(网络交互),输入一个“网址”,就会触发和对应的服务器的一次交互过程,这里也就是 HTTP请求,服务器收到了这个请求,需要返回给客户端一个结果(你输入了啥,想搜索什么关键字),经过计算处理,再通过HTTP协议交互,就会返回一个 HTTP响应,浏览器页面就会显示出你想要的结果。
1.1 HTTP 协议格式
HTTP 是?个文本格式的协议. 可以通过 浏览器 “开发者工具”(F12 / Fn+F12), 或者 Fiddler抓包工具 分析 HTTP 请求/响应的细节。
这里我使用的 Fiddler 工具相当于是一个“代理”,用来展示 客户端(浏览器前端) 和 服务器(浏览器后端) 交互的数据细节。
浏览器访问 baidu.com 时, 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给 baidu 的服务器. 当 baidu 服务器返回数据时, Fiddler 拿到返回数据, 再把数据交给浏览器.
因此 Fiddler 对于浏览器和 baidu 服务器之间交互的数据细节, 都是非常清楚的.
HTTP 是前后端交互的基石
1.1.1 分析一个HTTP请求
请求分为 4 个部分:
- 请求行(首行),包含三个部分
① HTTP 的方法,方法就是这个请求是什么类型的,一般有:GET/POST ② URL 请求地址,描述了要访问的网络上的资源是在哪 ③ 请求的 HTTP 版本号 - 请求头(header),包含了很多行
每一行都是一个键值对,键和值之间用":空格"来分割。 - 空行,相当于请求头结束的标记
空行的作用也是为了分隔第二部分(请求头)和第三部分(请求正文)。 - 请求正文(body),可以有也可以没有
1.1.2 分析一个HTTP响应
响应分为 4 个部分:
- 首行,包含三个部分
① HTTP 版本号 ② 状态码,描述了这个相应是一个表示"成功"还是"失败"。不同的状态码,描述了失败的原因。 ③ 状态码的描述,通过一个/一组简单的单词,来描述当前状态码的含义 - 响应头(header),包含了很多行
每一行都是一个键值对,键和值之间用":空格"来分割。 - 空行,相当于响应头结束的标记
- 响应正文(body)
相应正文的可能有各种不同的格式,内容就是服务器返回给客户端的具体数据。
1.1.3 协议格式图解
为什么 HTTP 报文中要存在 “空行”?
- 因为 HTTP 协议并没有规定报头部分的键值对有多少个. 空行就相当于是 “报头的结束标记”, 或者是 “报头和正文之间的分隔符”.
- HTTP 在传输层依赖 TCP 协议, TCP 是面向字节流的. 如果没有这个空行, 就会出现 “粘包问题”(数据传输没有结束标示就会出现的一种数据混乱现象)
2. HTTP请求详细解释
2.1 请求地址 URL
URL 其实就是我们一般称作的“网址”,它的全称是:(Uniform Resource Locator 统一资源定位符)。
为什么可以通过互联网进行信息交互,其他主机上的信息为什么可以通过另外的主机获取到? 其实这就跟我们本地文件的原理一样,我们自己电脑上的每一个文件们都有他独有的保存地址,我们通过这个本机地址可以访问到电脑上的所有文件。
那么不难想象,互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
下面我们来分析一个具体的 URL :
https://v.baidu.vip/personInf/student?userId=10000&classId=100
https : 协议方案名, 描述了当前这个 URL 是给那个协议来使用的。user:pass : 登陆信息.,现在的网站进行身份认证一般不再通过 URL 进行了.(不安全) 一般都会省略。v.baidu.vip : 服务器地址,描述当前要访问的主机的地址。此处是一个 “域名”, 域名会通过 DNS 系统解析成一个具体的 IP 地址.端口号(0-65535) : 表示当前要访问的主机上的哪个应用程序。上面的 URL 中端口号被省略了,当端口号省略的时候, 浏览器会根据协议类型自动决定使用哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口。/personInf/student : 带层次的文件路径,描述了当前要访问的服务器的资源是什么。userId=10000&classId=100 : 查询字符串(query string). 本质是一个键值对结构, 键值对之间使用& 分隔. 键和值之间使用= 分隔。这一部分本质上是浏览器/客户端给服务器传递的自定义的信息,相当于对获取到的资源提出了进一步的要求。片段标识 : 描述了要访问当前的 html 页面中的哪个具体的子部分,能够控制浏览器滚动到的相关位置。此 URL 中省略了片段标识。
2.2 关于 URL encode / decode
当 query string 中如果包含了特殊字符,就需要对特殊字符进行转义 这个转义的过程,就叫做 url encode,反之,把转义的字符还原回来,就叫做 url decode
像 / ? : 等这样的字符,已经被url当做特殊意义理解了,因此这些字符不能在你的 query string 中随意出现。 比如,某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义。urlencode转义的规则如下: 把要转义的内容的 ascii 码值取出来,用 “十六进制” 表示,同时加上 ‘%’ 每个字节都分别这样处理,就能得到最终的转义结果。
urlencode?具
2.2 认识 “方法”
HTTP 中引入的这些方法的初衷是为了表示不同的 “语义”。 但是随着时间的推移,这些表示“语义”的方法就都被浓缩成了 GET 和 POST ,程序员在使用的时候,既然都可以用,也就没有考虑 语义 这个事了~
这里只是罗列了 HTTP1.1 版本的方法
GET 方法
GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源. 在浏览器中直接输入 URL, 此时浏览器就会发送出?个 GET请求。
GET 请求的特点
- 首行的第?部分为 GET
- URL 的 query string 可以为空, 也可以不为空.
- header 部分有若干个键值对结构.
- body 部分为空(一般情况).
POST 方法
POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面). 通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求.
POST 请求的特点
- 首行的第?部分为 POST
- URL 的 query string ?般为空 (也可以不为空)
- header 部分有若?个键值对结构。
- body 部分?般不为空。 body 内的数据格式通过 header 中的
Content-Type 指定,body 的?度 由 header 中的 Content-Length 指定.
为什么一般"登录功能"要用 POST
因为登录功能要给服务器传递用户名和密码,如果使用 GET 请求,用户名和密码习惯就会放到 URL 的 queue string 中来传递 (此时由于加密机制,浏览器地址栏里的路径就会变成很长的一串),这个时候就会影响用户的体现。 并且更早的很多网站,就是把密码明文提交的,当 URL 中显示出了用户登录密码,也是非常不可取的。(但是这不能是不安全的体现,因为无论是 GET 还是 POST 要想不被获取到重要信息,都必须使用加密,否则 POST 也是可以被抓包拿到的。)
经典面试题:GET 和 POST 的区别
- 首先先下定论:GET 和 POST 没有本质区别(可以相互替代使用),具体来说,相当于:GET 能使用的场景,也能替换成 POST;POST 使用的场景,也能替换成 GET。
- 语义上的区别:GET 通常是用来取数据的;POST 通常用来上传数据。
- 细节上:通常情况下,GET 是没有 body 的,GET 通过 query string 向服务器传递数据;通常情况下,POST 是有 body 的,POST 通过 body 向服务器传递数据。
- GET 请求一般是幂等的,POST 请求一般是不幂等的。
幂等:每次你相同的输入,得到的输出结果是确定的, 不幂等:每次你相同的输入,得到的结果是不确定的。 - GET 可以被缓存,POST 不能被缓存。(缓存:提前把结果记住)对应于第 4 条。
2.3 认识请求 “报头” (header)
header 的整体的格式也是 “键值对” 结构,每个键值对 占?行, 键和值之间使用分号分割。 不同的键值对表示了不同的含义,来描述请求报头在发送请求时的更多信息~ 以下介绍一些常见的键值含义。
Host
表示服务器主机的地址和端?。
Content-Length
表示 body 中的数据?度。
我们前面有提到过,在 HTTP 请求/响应 格式中,header 和 body 中间会有一个空行来分割,以避免出现在读取数据时的 “粘包” 问题。
而如果,我们当前有若干个 POST 请求,这个时候若干个请求一起到 TCP 的缓冲区了,就没有所谓的 “空行分割” 这样的格式了,所以要有 Content-Length 这样规定的长度,表明了这个 POST 请求的 body 长度,以保证正确读取。
Content-Type
表示请求的 body 中的数据格式。
常见选项:
application/x-www-form-urlencoded : form 表单提交的数据格式. 此时 body 的格式形如:
title=test&content=hello
multipart/form-data : form 表单提交的数据格式(在 form 标签中加上 enctyped="multipart/form-data" ,通常用于提交图片/文件. body 格式形如:
Content-Type:multipart/form-data; boundary=----
WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
application/json : 数据为 json 格式. body 格式形如:
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05cc
de64b16a861fa2bddfdcd15"}
User-Agent (简称 UA)
表示浏览器/操作系统的属性(用户是用什么样的设备来上网的)。
这些信息是提供给服务器的一些相关自己设备的信息,服务器会根据这些不同的设备信息,返回给用户设备最兼容的一套响应来展示出来。
Referer
表示这个页面是从哪个页面跳转过来的. 形如
Referer: https://v.baidu.vip/login
如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的。
理解 Cookie
Cookie 是浏览器给页面提供了一种能够持久化(写到磁盘里)存储数据的机制。 Cookie 中存储了?个字符串, 这个数据可能是客户端(网页)自行通过 JS 写入的, 也可能来自于服务器(服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据),往往可以通过这个字段实现 “身份标识” 的功能。
浏览器为了安全,默认情况下是不能让页面的 JS 访问到用户电脑上的文件系统的。但是这样的安全限制,也带来了一些麻烦,有时候又需要让页面持久化的存储一些数据(比如,记住用户名密码方便下次直接登录)。 因此,就会使用 Cookie 这种策略,比如:在用户登录页面完成身份验证之后,此时服务器就会给浏览器返回一个用户的身份信息,浏览器把这个信息就保存在一个特定的位置上,后续再访问同一网站的其他页面的时候,浏览器再自动的带上这个身份信息,服务器就可以直接识别了。
每个不同的域名下都可以有不同的 Cookie, 不同网站之间的 Cookie 并不冲突。
Cookie 具体组织形式:
Cookie 数据是从哪里来的:
其实是服务器返回给客户端的,我们用 Fiddler 抓包来观察一个登录请求的 服务器 响应: 在服务器返回给客户端的 header 中,包含这样一组键值对,其实就是服务器完成身份认证之后,就给客户端返回了一些具体的信息。信息就是通过 Set-Cookie 这样的"响应报头"来表示的,客户端就会根据服务器返回的这些之前保存过的用户信息去进行后续的访问了。
理解登陆过程:
理解会话机制 (Session)
服务器同?时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系。
- 当用户登陆的时候, 服务器在 Session 中新增?个新记录, 并把 sessionId / token 返回给客户端. (例 如通过 HTTP 响应中的 Set-Cookie 字段返回).
- 客户端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId/ token. (例如通过 HTTP 请求 中的 Cookie 字段带上).
- 服务器收到请求之后, 根据请求中的 sessionId / token 在 Session 信息中获取到对应的用户信息, 再进行后续操作.
Cookie 和 Session 的区别
- Cookie 是客户端的机制. Session 是服务器端的机制.
- Cookie 和 Session 经常会在?起配合使用, 但是不是必须配合.
- 完全可以用 Cookie 来保存?些数据在客户端. 这些数据不?定是用户身份信息, 也不?定是 token / sessionId
- Session 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递.
2.4 请求正文(body)
请求正文中的内容一般是根据 Content-Type 规定的格式来返回信息的,不同的请求的需求都是不一样的,这里对内容就无法做过多讨论,下面是关于请求正文集中格式的介绍。大家都可以自己通过抓包来观察。
application/x-www-form-urlencoded : form 表单提交的数据格式. 此时 body 的格式形如:
title=test&content=hello
multipart/form-data : form 表单提交的数据格式(在 form 标签中加上 enctyped="multipart/form-data" ,通常用于提交图片/文件. body 格式形如:
Content-Type:multipart/form-data; boundary=----
WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
application/json : 数据为 json 格式. body 格式形如:
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05cc
de64b16a861fa2bddfdcd15"}
3.HTTP 响应详解
HTTP 响应和 HTTP 请求的大致格式都是相似的,这里我们主要介绍一下响应其他的重要信息。
3.1 认识 “状态码” (status code)
状态码表示访问一个页面的结果。(是访问成功, 还是失败,还是其他什么情况)
常见的状态码:
200 OK
最常见的状态码,表示访问成功,浏览器顺利的获取到需要的内容了。
404 Not Found
没有找到资源,表示要访问的资源不存在。
403 Forbidden
表示访问被拒;虽然资源存在,但是你没有权限访问。
405 Method Not Allowed
前面我们已经介绍了 HTTP 中所支持的方法, 有 GET, POST, PUT, DELETE 等 但是对方的服务器不一定都支持所有的方法(或者不允许用户使用一些其他的方法的情况)。
500 Internal Server Error
服务器出现内部错误,一般是服务器的代码执行过程中遇到了一些特殊情况(服务器异常崩溃)会产生这个状态码。
504 Gateway Timeout
服务器太繁忙,当服务器负载比较大的时候,服务器处理单条请求的时候消耗的时间就会很长,就可能会导致出现超时的情况。
502 Bad Gateway
网关错误
302 Move temporarily
临时重定向 在登陆页面中经常会见到 302,用于实现登陆成功后自动跳转到主页。
响应报文的 header 部分会包含一个 Location 字段,表示要跳转到哪个页面。
301 Moved Permanently
永久重定向 当浏览器收到这种响应时,后续的请求都会被自动改成新的地址。
301 也是通过 Location 字段来表示要重定向到的新地址。
小结:
3.2 认识响应 “报头” (header)
响应报头的基本格式和请求报头的格式基本一致。
Content-Type
text/html : body 数据格式是 HTMLtext/css : body 数据格式是 CSSapplication/javascript : body 数据格式是 JavaScriptapplication/json : body 数据格式是 JSON
关于 Content-Type 的详细情况
3.3 认识响应 “正文” (body)
正文的具体格式取决于 Content-Type。
这里就不抓包给大家展示了~
以上就是关于 HTTP 协议的相关内容,后面还会补充上关于 HTTPS 相关介绍。
|