努力经营当下,直至未来明朗!
开启后端学习之旅:
一个人最大的痛苦来源于对自己无能的痛苦!
- 网络技术中,最核心的概念就是“协议”。
- HTTP (全称为 “超文本传输协议”) 是一种应用非常广泛的 应用层协议。
- HTTP就是应用层典型的协议。
- 应用层,很多时候需要程序员自定义应用层协议,但是也有一些现成的协议供我们直接使用。
HTTP的应用:
① 浏览器和服务器之间的交互(打开网页),大概率都是HTTP协议
② 手机APP和服务器之间的交互,大概率都是HTTP协议
③ 服务器之间的相互调用,也可以使用HTTP
(①②是主流,③非主流)
当前最新的HTTP版本是HTTP3.0,但是当下最常见的版本还是HTTP1.1,所以目前主要介绍的是1.1版本。
在浏览器中输入一个网址,等待网页生成的过程其实就是 浏览器和服务器通过HTTP进行交互了。
HTTP协议是典型的“一问一答”模型的协议(也就是请求和响应一一对应)
学习HTTP协议,主要学习的就是HTTP放入报文格式:报文格式描述了HTTP请求和响应是啥样的
需要使用“抓包工具”来捕获到请求交互的详细情况。
“抓包工具”:是个特殊的软件,相当于一个“代理程序”,浏览器给服务器的请求就会经过这个代理程序(响应也是经过该代理程序的),进一步的就能分析出请求和响应的结果如何。
谈到“代理”,其实是分为两种的:
① 正向代理:给客户端提供服务的,和客户端关系紧密(站在服务器的角度,正向代理把真正的客户端给隐藏起来了,服务器并不知道真正的客户端是啥)
② 反向代理:给服务器提供服务的,和服务器关系紧密(站在客户端的角度,反向代理把真正的服务器给隐藏起来了,客户端并不知道真正的服务器是啥)
抓包工具有很多,我们使用fiddler(其他的如:wireshark,Charles,Chrome的开发者工具等),fiddler使用简单、功能强大,很多公司都在使用。
下载安装fiddler:
【补充一个好用的网站:cn.bing.com/ (很多都可以在上面搜)】
① cn.bing.com/ (当然也可以直接在浏览器上搜索)
②搜fiddler:进入官网,选择经典版
③ 下载安装后打开fiddler:
- 左侧区域是抓到的请求/列表,应用程序通过http传输数据都能被fiddler抓到;
- 双击左侧某个你想关注的请求详情,就会在右侧窗口显示出请求的具体情况。
- 点击右上角的raw标签页显示的是HTTP 请求最原始的样子,右下角的raw标签页显示的是HTTP 响应 最原始的样子。
(由于响应数据可能体积较大,服务器通常会返回一个“压缩”后的结果,点击上面的黄色的条条就可以进行解压缩了)
④ 注意事项:
可能会存在不一定能够抓取到很多请求的情况,那么:
A. 需要开启fiddler抓取HTTPS的功能(现在互联网上纯HTTP很少了,更多的是HTTPS,HTTPS可以理解为升级版本的HTTP,即在HTTP的基础上加了个加密层)
手动开启:菜单栏=> tools => options => HTTPS中4个选项全勾√ 上 => 点击ok => 首次勾选点击ok后会提示是否安装“根证书”,务必点击“是”!!!
B. 如果开启了上述HTTPS,也安装了根证书,但是还是抓不到:检查电脑上是否安装了其他的代理程序/代理作用的浏览器插件(如:工具/游戏加速器/steam++等本质上都是代理,这些程序都会和fiddler打架,也就是说:都可以安装,但是不能同时运行!)。使用fiddler务必要把其他的代理程序禁用/关闭。
(在fiddler中点击右边view可以在记事本中详细查看)
HTTP是一个文本格式的协议。(行文本)
3)空行:一个HTTP请求的header可以有若干个,就使用空行作为header的结束标记,就类似于链表的null。(重点了解)
4)正文body:有的请求有,有的没有。格式很多,最常见的就是json。
(这是某个网站登录请求的正文)
补充:如何清空fiddler中左侧抓到的请求?
先选中一个 -> Ctrl+A -> delete
完整的HTTP响应的格式:
1)首行:
① HTTP/1.1 :版本号
② 200是状态码,一般用200表示请求成功
(其实大多数响应后面还会有一个ok,表示状态码的描述,就是对状态码表示解释说明)
③ 响应报头:同样也是键值对的结构
③ 空行
④正文:可以是json、html、css、js、图片等
为什么HTTP报文中要存在空行?
① 因为 HTTP 协议并没有规定报头部分的键值对有多少个, 空行就相当于是 “报头的结束标记”, 或者是 “报头和正文之间的分隔符”.
② HTTP 在传输层依赖 TCP 协议, TCP 是面向字节流的。如果没有这个空行, 就会出现 "粘包问题"。
认识URL:唯一资源定位符 (用这个来找到网络上的资源)-》 也就是:浏览器地址栏的内容
区别:URI唯一资源标识符(用这个来区分网络上的资源)
【这两个概念非常相似,很多时候我们是不会进行显示区分的】
URL里面是啥样的,是由“RFC标准文档”来进行描述的。RFC标准文档描述了很多网络中的协议标准,包括IP、UDP、TCP、HTTP等
URL并非是HTTP独有的,很多协议都是可以使用的
HTTP服务器一般不会把电脑上所有的资源都提供到网络上,通常都是指定某个目录,把目录里的作为网络可访问的资源。
HTTP服务器都是可以在启动的时候指定绑定某个端口的,但是在大多数情况下HTTP服务器默认使用的端口号就是80.包括在浏览器中写一个URL也不一定要写端口号,如果不写就相当于默认访问http80端口,https是443端口。
【访问静态资源:访问硬盘的真实文件; 访问动态资源:直接在内存中根据请求进行构造文件】
URL中 ?后面内容:query string查询字符串:相当于浏览器给服务器传递的一些必要的参数。
此处的查询字符串是通过“键值对”格式来组织的,键值对之间使用**&分割**,键和值之间使用**=来分割**。
如:https://editor.csdn.net/md?not_checkout=1&articleId=128333065
(editor.csdn.net会通过DNS域名解析系统解析为一个具体IP地址)
HTTP header中也是有很多键值对的,这里的键和值大多都是标准规定好的(虽然也可以自定义,但是以标准规定为主)
而URL里的查询字符串中的键值对完全是自定义的。
因此,查询字符串就是前后端交互数据的重要桥梁!
片段标识符:用来区分一个网页中的哪个部分,常见于小说网站或者文档网站。借助片段标识符快速跳转到网页的某个部分。
URL重要的部分:
① IP地址+端口号(基础)
② 带层次的路径(开发中常用)
③ 查询字符串(开发中常用)
URL中已经包含了一些特殊含义的符号了,如:/ ? @ …但是万一query
string中也包含了这些符号就可能会出现问题(浏览器可能会错误识别URL,服务器也可能会错误解析URL),这就非常类似于编程语言里面的变量名不能是“关键字”。
此时就使用URL encoding对特殊符号进行转义,但是转义的不仅仅是这些特殊符号,还有汉字。
使用URL encoding对特殊符号、汉字进行转义,转义的规则:就是把待转义的字符串的每个字符用十六进制进行表示,每个字节前面加个 % (注:UTF8中每个汉字3字节,具体十六进制可以查看utf8文档)
把原始字符转成转义后的字符:URL encode(编码)
把转义后的字符还原成原始的字符:URL decode(解码)
【写代码经常要考虑到编码、解码,但是有第三方库可以使用,只不过我们一定要有这个意识!!】
(可以搜索网上的 URLencode在线编码解码工具)
GET、POST是最重要的!可以应对90%以上的场景
浏览器地址栏直接输入URL,此时就会触发GET
html中的link,a,img,script也会触发GET请求(请求指定页面信息,并返回实体)
form表单:html中的form标签,可以构造出GET请求
ajax:(后面讲)
【补充】在页面上按住ctrl之后再点击刷新(其实也就是ctrl+f5)是强制刷新,能够在fiddler中看到更多请求。
浏览器在加载页面的时候,往往要加载这个页面依赖的很多其他资源,如css,图片,js等,加载这些资源显然是需要消耗一定的时间的。为了提高页面加载效率,浏览器就会对加载过的这些css,图片,js等进行缓存,也就是直接保存在本地磁盘上。下次再访问同一个网页时,之前的css,图片,js等就不必从网络上加载,而是直接从硬盘读取就行。使用ctrl+f5强制刷新就可以让浏览器不走缓存,而是直接强制重新从网络上获取资源。
① 首行的第一部分为 GET
② URL 的 query string 可以为空, 也可以不为空.
③ header 部分有若干个键值对结构.
④ body 部分为空.
(如果需要给服务器传递一些参数,这些参数通常就是通过query string进行传递的)
(POST一般是在登录页面比较常见)
① 首行的第一部分为 POST
② URL 的 query string 一般为空 (也可以不为空)
③ header 部分有若干个键值对结构.
④ body 部分一般不为空.
⑤ body 内的数据格式通过 header 中的 Content-Type 指定.
⑥ body 的长度由 header 中的 Content-Length 指定.
POST在传递信息给服务器的时候,通常就会把信息给放到body中。
【经典面试题】GET和POST的区别:
1)先盖棺定论:GET和POST没有本质区别(即:GET和POST使用的场景基本可以相互代替)
2)细节上谈区别:
① 语义上:GET的语义是“从服务器获取数据”,POST的语义的“往服务器提交数据”
② 使用习惯上:给服务器传递的数据,GET通常是放在url的query string中的,POST通常是放在body中的。
③ GET请求建议实现成“幂等”的,POST一般不要求实现“幂等”。
(幂等:简单来说大概就是输入是确定的,输出结果也就是确定的,即输入一样时输出也是一致的)
【设计服务器的时候,就需要提供一些“接口/API”:API传入的参数就视为输入,API返回的结果就视为输出。
基于GET的API一般会建议设计成幂等的,基于POST的API则无要求(建议不要求一定要遵守)】
④ 在幂等的基础上,GET的请求结果是可以缓存的(浏览器默认行为);POST则一般不会缓存。
如果当前GET确实是幂等的,就不必处理,直接让浏览器缓存没问题;
但是如果当前的GET不是幂等的,就需要通过特殊技巧避免浏览器产生缓存(典型的技巧就是让每次GET请求的URL都不相同,通过特殊的query
string来保证url不同)
HTTP没有加密功能,HTTPS具有一定的加密功能。 但是相对来说,实践中主要还是通过业务上代码来实现加密的。
① PUT 与 POST 相似,只是具有幂等特性,一般用于更新
② DELETE 删除服务器指定资源
③ OPTIONS 返回服务器所支持的请求方法
④ HEAD 类似于GET,只不过响应体不返回,只返回响应头
⑤ TRACE 回显服务器端收到的请求,测试的时候会用到这个
⑥ CONNECT 预留,暂无使用
URL中不是也有这个服务器主机的IP和端口吗,为啥还要搞个Host?
① 事实上,URL中的IP和端口 与 Host中的IP和端口不一定完全一样(当请求是经过代理来访问的时候可能不一样的,当然这一点在fiddler上没有体现出来)。
② 请求中的URL地址是经过的代理地址,而Host的地址是目标服务器的地址。
如果请求没有body就没有这两个字段(如GET一般是没有body的),反之则有(如POST一般是有body的)
HTTP协议在传输层是基于TCP的(至少在HTTP3.0之前是这样的,3.0就变成UDP了)。
TCP是面向字节流的,就会存在粘包问题。(所以在存在body时,Content-Length是很重要的,可以区分下一个HTTP)
Content-Length不需要手动设置,一般是浏览器和HTTP服务器自己计算好的。
Content-Type也是很重要的:body中的数据可以放很多种格式,存的不同格式的数据,对于接收方来说,对应截然不同的解析方式。
三种Content-Type选项:
面试一般不会考这三种选项,但是对于日常开发/调试时很有用的,通过抓包以及代码来熟悉。
① application/x-www-form-urlencoded: form 表单提交的数据格式。 此时 body 的格式形如:
title=test&content=hello
// 和query string格式一样使用键值对,键值对之间&,键和值之间=
② multipart/form-data: form 表单提交的数据格式(在 form 标签中加上
enctyped=“multipart/form-data” . 通常用于提交图片/文件。
(这个格式主要在上传文件的时候会出现)
③ application/json: 数据为 json 格式. body 格式形如:
{"username":"123456789","password":"xxxx","code":"jw7l",
"uuid":"d110a05ccde64b16a861fa2bddfdcd15"}
(这个JSON格式比较香,所以大家都爱用。)
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
① Mozilla:其实就是之前提及的前端查文档使用的MDN的组织
② (Windows NT 10.0;WOW64):操作系统信息,Windows NT是操作系统内核
③ AppleWebKit/537.36:一个浏览器内核
④Chrome/86.0.4240.198:浏览器
⑤ Safari/537.36:mac电脑上默认的浏览器
系统不同,浏览器不同,设备不同,对于某些页面的支持程度可能是不一样的。所以通过UA来收集浏览器/操作系统的信息。进一步就可以知道该浏览器/系统都支持啥样的页面了。
也是请求头中一种重要的数据
是浏览器在本地存储数据(存到硬盘上)的一种机制。
服务器保存了大部分信息,但是浏览器也需要保存一些特殊的信息,为了保证数据的持久化存储就需要保存到硬盘上;但是浏览器为了安全起见,禁止网页的js访问你的电脑的硬件(文件系统)。所以,浏览器专门提供了特殊的API给网页来用,可以让网页来存储一些简单的数据。
补:浏览器提供的持久化存储方案有很多:
① Cookie:是最经典的一种方案(最老)
② LocalStorage:是比较新的一种方式
③ IndexDB:是更新的方案
每个键值对中都有:key、value、cookie的有效范围(域名+路径)。
Cookie 和 query string一样,都是程序员自定义的。
注意区分:
① Cookie不是缓存,是持久化存储数据的手段。
② Cookie和GET没直接关系,其他的POST、PUT啥的也都有cookie。
③ 持久化存储是保存在硬盘上的,这个数据你想咋用就咋用
④ 缓存里的数据不是持久化的(也可以在内存中缓存),缓存的数据是用来“提高访问速度” 的。
Cookie中的键值对都是保存的简单字符串,如果想让其存储个图片、视频、flash啥的是万万做不到的。
比如,可以使用Cookie存:
①上次访问页面的时间
②当前页面的访问次数
③当前访问页面的身份信息
…
(具体存啥是由程序员自己定义的,不是浏览器自动存的)
Cookie是存在浏览器中的,但是来源是服务器,还要再回到服务器。
①当我们的浏览器访问了服务器之后,在服务器返回的响应报文中,可以在响应header中包含一个/多个Set-Cookie这样的资源,浏览器看到Set-Cookie就会把这些数据保存在浏览器本地(Set-Cookie是程序员在服务器代码中构造出来的)
②当浏览器保存了Cookie之后,下次浏览器访问同一个网站时,就会把之前本地存储的Cookie再通过http请求header中的Cookie给带过去。
③ 为啥要转一圈呢?因为服务器要服务的客户端是很多的,这些不同的客户端应该要有不同的数据。
(Cookie会占硬盘,但是空间不大,而且会有到期时间)
【很多网站是基于Cookie实现的,但是也有很多新的网站不是使用Cookie,而是使用如LocalStorage之类的进行实现的】
(key是身份信息,value是详细信息)
【Cookie中的用户身份标识就是sessionId,而服务器上的用户的信息就是session/会话。
Cookie只针对当前域名下的网站生效(其实就相当于就诊卡只针对某个特定医院生效)】
举例:医院看病(刷卡就是Cookie)
路径一般是/,意思就是在整个网站下的所有路径都是生效的。但是有些页面特殊,需要特定的cookie,这些特定的cookie在别的页面中无意义。
(请求报文的body:GET一般是没有的,POST一般是有的)
正文中的内容格式和 header 中的 Content-Type 密切相关,其三种方式也就是三种Content-Type选项。(了解)