|
JavaEE
【前端】JavaScript —— JS的基本语法之数组, 函数…
【前端】JavaScript —— WebAPI
应用层最广泛使用的协议只有 (主要是学习报文格式)
借助抓包工具, 来分析 HTTP
协议, 本文使用的抓包工具是 fiddler
(还有其他的一些, wieshark, Charles, chrome 等开发者工具)
推荐下载 classic 版本
我们双击打开 fiddler
在响应数据中
# 注意事项 #
有的人可能抓不到想要抓的请求
需要开启 fiddler 抓取 HTTPS
的功能 (现在互联网上纯 HTTP 很少了, 更多的是 HTTPS . HTTPS 可以理解成升级版本的 HTTP, 在 HTTP 的基础上, 加了个加密层)
首次勾选的时候, 点击 ok 后, 就会提示一个, 是否需要安装 “根证书”, 务必要点击 “是”
如果开启了上述 HTTPS
也安装了根证书, 还是抓不到. 检查是否你的电脑上安装了其他代理程序/ 代理作用的浏览器插件
- 一些游戏加速器/ steam++… 本质上都是代理
- 这些程序都会和 fiddler 打架, 可以同时装, 但是不能同时运行
下面我们来结合 fiddler 了解一下协议格式, 我们点击 “View Notepad
” 用记事本查看.
我们先来查看 HTTP
请求, HTTP 是一个文本格式的协议 (构造一个 HTTP 请求, 本质上就是往一个 TCP socket
中, 按照下列格式写入数据即可)
首行 (方法 URL 版本号)
请求头 header
空行 (一个 HTTP 请求的 header
可以有若干个, 就使用空行. 作为 header 的结束标志, 类似于 链表的 null
)
正文 body
(有的请求有, 有的请求没有)
- URL 唯一资源定位符 (用这个来找到网络上的资源)
- URI 唯一资源标识符 (用这个来区分一个网络上的资源)
- 这个两个概念非常相似, 很多时候, 不会显式区分
URL
就是浏览器地址栏里的一串地址
URL 里面是有 “RFC 标准文档” 来进行描述的
RFC 标准文档: 描述了很多网络中的协议标准, 包括 IP, TCP. UDP, HTTP…
- 如果我们想查看某个协议中的具体的细节, 应该搜索对应的文档编号, 比如URL 的详细规则由 因特网标准
RFC1738
进行了约定.- 我们可以通过搜索 xx RFC 来得知 xx 相对应的文档编号
# 注意 #
URL 并非是 HTTP 独有的, 是给很多协议都能使用的.
下面我们来通过下面这串地址来更好的了解 URL
URL 需要定义到具体的资源, 这里就通过我们后面的带层次的文件路径来进行确定
下面我们来举两个例子, 来更好的了解带层次的文件路径
#
真实存在的文件 (访问静态资源)
#
虚拟出来的文件 (访问动态资源)比如:
可以在 HTTP 服务器中, 加入一个特殊的逻辑, 比如请求的 URL 中的路径是
/test
.就直接在 HTTP 服务器中, 直接在内存中构造出一个 HTML, 返回到浏览器这边 (此时, 没有访问硬盘的真是文件, 而是直接在内存中拼了个 HTML 出来)
小知识
: 在浏览器的 URL 里面端口号经常会省略不写, 省略的时候用的是当前协议的默认端口
https, 默认端口是 443
http, 默认端口是 80
我们来举一个例子:
此处的查询字符串, 是通过 “键值对” 格式来组织的
键值对之间使用
&
(按位与运算) 分割键和值之间, 使用
=
来分割
# 注意 #
HTTP header 也是有很多键值对, 这里的键和值大多都是标准规定好的(虽然也可以有自定义的, 但是以标准的为主)而 URL 里面的 查询字符串, 键值对, 完全是自定义的
比如: 每一个标题都是一个具体的片段 (同一个页面网址不断变化)
URL 中已经包含一些特殊含义的符号, 比如: / ? @
万一 query string 的 value 中, 也包含了这些特殊符号会怎么样呢?
很有可能会有问题(浏览器可能会错误的识别 URL, 服务器也可能会错误的解析 URL)
非常类似于, 编程语言里的 变量名 不能是 “关键字”
URL encode
本质上就是把特殊符号进行转义了, 这里转移的范围不仅仅是这些特殊符号, 还有汉字…
比如: 如果此时我们在搜索框中搜索 “C++”
再比如: 我们搜索 “鸪鸠”
转译的规则, 就是把待转译的字符串, 每个字符的十六进制表示, 每个字节前加上一个 %
我们现在使用一个 utf8编码转换器
# 总结 #
HTTP 中非常重要的部分, 可以把 方法理解成, 这个请求想做什么
方法 | 说明 | 支持的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
最常用的 HTTP 请求方法
浏览器地址直接输入 URL
, 此时就会触发 GET
html 里面的 link, a, img, script 也会触发 GET 请求
href/ src
都会引用一个外部的资源, 本质上就是浏览器会重新发送一个 GET 请求, 来从服务器拿到对应的数据比如:
我们使用 fiddle
来看一下, 我们当前请求说蓝色字体的请求, 下面还有很多域名是 csdn 的请求, 都是当前页面 又给 csdn 服务器发送的其他的 http请求.
我们按住 ctrl 再刷新, 我们能看到更多的请求
- 浏览器在加载页面的时候. 往往要加载这个页面依赖的很多其他资源 css, 图片, js 等, 加载这些资源, 显然需要消耗不少时间的.
- 为了提高页面加载效率, 浏览器就会对加载过的这些 css, 图片, js 进行缓存 (保存在你本地的磁盘上)
- 下次再访问同一个网页, 之前的 css, 图片, js 就不必重新从网络加载, 而是直接读硬盘即可
- 使用 ctrl + f5 强制刷新, 就可以让浏览器不走缓存, 直接强制重新从网络上获取资源
form
表单 (html 里的 form 标签, 可以构造出 GET 请求)
ajax
GET 请求的特点
GET
header
部分有若干个键值对结构.如果需要给服务器传递一些参数, 这些参数通常就是通过 query string
来传过去
网上有这样的说法: GET 请求长度最多是 1KB/ 2KB/ 1MB…
⚠典型的错误说法
HTTP 协议由 RFC 2616 标准定义, 标准原文中明确说明: "Hypertext Transfer Protocol -- HTTP/1.1," does not specify any requirement for URL length
. 没有对 URL 的长度有任何的限制.
标准虽然没有谈到长度上限, 但是浏览器和 HTTP 服务器在实现的时候, 可能是有长度上限的, 也可能是没有的 (取决于具体的实现)
POST 应用场景 没有 GET 那么多
产生 POST 途径
form
ajax
POST 请求的特点
比如:
query string
的header
, 键值对的形式body
, body 的数据格式有很多种 (POST 在传递给服务器的时候, 通常会把信息放到 body 中)先盖棺定论, GET
和 POST
没有本质区别 (使用 GET 实现的场景, 基本都可以使用 POST 代替; 使用 POST 实现的场景, 也可以用 GET 来代替)
再来谈细节上的区别
GET
的语义, 是 “从服务器获取个数据”, POST
的语义, 是 “往服务器上提交个数据” (HTTP 协议设计的 “初心”)
使用习惯上, 给服务器传递的数据, GET
通常是放在 URL 的 query string 中, POST
通常是放在 body 中 (GET 也可以把数据放在 body 里, 但是很少见, 浏览器不一定能支持, 其他的 http 客户端是可以支持的; POST 也可以把数据放在 query string里, 但是很少见, 浏览器也是支持的)
GET
请求建议实现成 “幂等” 的, POST
一般则不要求实现成 “幂等”
设计服务器的时候, 就需要提供一些 “接口/ API”
API 传入的参数, 就视为是输入
API 返回的结果, 就视为是输出
幂等: 数学上的术语, 简单来说, 大概就是输入是确定, 输出结果也就是确定的
在幂等的基础上, GET
的请求结果是可以被缓存的, POST
则一般不会缓存
如果当前 GET 确实是幂等的, 就不必处理, 就让浏览器缓存, 没问题.
如果当前 GET 不是幂等的, 就需要通过特殊技巧避免浏览器产生缓存 (典型的技巧就是让每次 GET 请求的 URL
都不相同, 通过特殊的 query string
来保证 URL 不同)
网上有这样的说法: POST 比 GET 更安全
依据是:
GET
是把参数放到 URL 中, 如果你实现登陆页面, 一点登录, 你的用户名和密码就直接以 query string 的形式放到 URL
里面了, 就直接显示到浏览器地址栏中了, 会被别人看到, 所以不安全.
POST
是把参数放到 body 中, body
不会显示到浏览器页面上, 多以就不会直接显示出来, 所以更安全
⚠典型的错误说法
虽然把用户名密码放到 URL
里确实不好, 但是放到 POST 的 body
中也没有更安全, 不能说 “不在界面上显示” 就是安全! !
只要你代码里没有进行加密, 此时就谈不上安全.
header 的整体的格式也是 “键值对” 结构, 每个键值对占一行. 键和值之间使用分号分割.
这里的键值对, 都是标准规定的, 有特定含义的, 当然这里也可以放一些自定义的键值对.
Host 表示服务器主机的地址和端口
比如:
这里的端口可以省略, 省略则表示默认值
URL 中不是也有这个服务器主机的 IP 和端口, 为什么还需要一个 Host?
事实上, URL
中的 IP 和端口, 在 Host
里的 IP 和端口, 不一定完全一样.
当我们的请求是经过代理来访问的时候, 是可能会不一样的 (在 fiddler
中没有体现出来)
Content-Length
: 表示 body 中的数据长度
Content-Type
: 表示请求的 body 中的数据格式
这两个字段不一定有, 但如果有一个, 就会有另一个
如果请求没有body (GET) 就没有这两个字段
如果请求有 body(POST) 就一定有这两个字段
Content-Length 不需要咱们手动来设置, 一般都是浏览器和 HTTP 服务器, 自己计算好的
Content-Type
body
中的数据可以放很多种格式, 存不同的格式, 对于接收方来说, 解析方式是截然不同的.
常见选项:
application/x-www-form-urlencoded: form
表单提交的数据格式. 此时 body 的格式形如:
title=test&content=hello
(这个格式和 query string
是一样的, 并且这里也是需要 URL encode 的)
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":"d110a05ccde64b16a861fa2bddfdcd15"}
我们使用 fiddler
抓一下 我的主页. 其中有这样一行:
小结
:
UA
中主要包含到的信息, 就是操作系统信息 和浏览器信息, 描述了用户使用什么样的设备上网
系统不同, 浏览器不同, 设备不同, 对于某些页面的支持程度也是不一样的
现在的设备之间的差别已经比较小, 上古时期则不是.
浏览器的发展不是一蹴而就的, 是一个循序渐进的过程
- 最早的浏览器只支持文字
- 后来, 开始支持图片
- 再后来, 能够支持 JS
- 再后来, 能够支持音频/ 视频
- …
同一个时间段内, 可以存在着好多种浏览器
#
此时, 网站的开发者就犯难了.
这时就想出了一个解决办法: 通过 UA 来收集到浏览器/ 操作系统的信息, 进一步就知道这个浏览器/ 系统都支持啥样的页面了
#
随着时间的推移, 浏览器发展发展, 殊途同归了
网站的开发者就不必再过多的纠结浏览器的兼容问题了, UA 就已经完成了历史使命了.
#
当然现在 UA 仍是有用的
可以根据 UA 来识别出 PC, 平板, 手机…分别开发出不同版本的页面
#
但这样使程序员的工作量增加了, 程序员就想了个办法, 发明了个技术, “响应式页面
”
通过特殊的 CSS 和 JS, 感知当前浏览器窗口的尺寸
根据不同尺寸, 重新排列页面布局, (目前很多网站都是这么做的, 写一份页面, 兼容多个设备)
#
UA 的作用确实有进一步被削弱了, UA 即使失去了最初的作用, 但是至少可以用来在服务器统计用户的设备情况 (大数据时代)
我们先来看一个例子:
我们通过该页面点进第一个博客, 并对其进行抓包, 我们发现有一行 Referer
我们可以发现, Referer 中的网址和主页的网址是一样的.
Referer
指的就是, 当前这个页面, 是从哪个页面跳转过来的(上级页面).
# 注意 #
在浏览器地址栏直接输入一个地址, 没有 Referer
直接点收藏夹, 也没有 Referer
使用 Referfer 的典型例子: 按照点击计费 (CPC 广告)
在浏览器上有许多广告. 当我们点击广告, 就会跳转到广告主的 “落地页”, 这个点击操作, 广告主就需要付钱. (浏览器给广告主的网站导入流量了, 导入的流量就会促使一部分人去消费)
浏览器导流 => 广告主的网站曝光机会就会增加 => 促使更多的成交订单
这就就需要统计点击的次数. 根据点击的次数, 和广告主来结算广告费.
那实际点了多少次, 由谁来统计呢?
双方都统计, 然后看双方统计数量是否一致.
有没有可能, 请求中的referer被改了呢?
比如: 某公司 B, 也有自己的广告平台. 将本来是 公司A 的 referer
改成了自己的 referer. 这就相当于, 把本来是 公司A 的钱, 变成了自己了.
因此务必得在技术上进行反制, 关键要点: 不能让运营商随便的来解析咱们的请求. 或者即使解析了, 也不能随意的修改. 核心就是: 加密 => HTTPS
也是请求头中的一个重要字段, 是浏览器在本地存储数据的一种机制
浏览器专门提供了特殊的 API
给网页使用, 可以让网页存储一些简单的数据
浏览器提供的持久化存储方案, 有好几种:
Cookie
是最经典(最老) 的一种方案. (重点介绍)LocalStorage
是比较新的一种方案.indexDB
是更新的方案.我们当前浏览器已经保存很多 Cookie
了
Cookie
是按照域名维度来组织的
不同的域名下有不同的 Cookie
一个网站发起的 http
请求可能是来自于多个域名的
Cookie
这里的键值对都是简单的字符串
你使用 Cookie 作为保存数据的手段, 只能存一些简单的键值对信息, 简单的字符串 (如果想让它存个图片, 存个视频…, 是万万做不到的)
比如: 可以用 Cookie 存:
- 上次访问页面的时间
- 当前网页的访问次数
- 当前访问页面的身份信息 (身份标识, id)
# 注意事项 #
Cookie
不是缓存, 是持久化存储的手段
持久化存储不是缓存, 持久化存储, 是保存在硬盘上的.
缓存里的数据不一定是持久化的 (也可以在内存里缓存)
Cookie
只在对应的域名下生效
大部分路径都是 / . 意思是在整个网站下, 所有的路径都是生效的. (有些页面特殊, 需要特定的 Cookie, 这些特定的 Cookie
在其他页面中无意义)
Cookie 从哪里来的
Cookie
是存在浏览器的, 来源是服务器
Cookie 到哪里去
Cookie
来自于服务器, 存储于浏览器, 还要再回到服务器
当浏览器保存了 Cookie 之后, 下次浏览器访问同一个网站, 就会把之前本地存储的 Cookie 再通过 http 请求 header
中的 Cookie 给带过去.
Cookie 典型应用场景
最常用的场景就是在客户端维持登陆状态
在某个网站上登陆成功后, 浏览器就会机制当前登录用户的身份信息, 然后接下来访问网站的其他页面, 服务器也能知道咱们是谁在登陆.
很多网站都是基于这一套来实现的 (也不是 100%, 现在有很多的网站, 就不再使用 Cookie
来进行本地存储. 可以用 localStorage
之类的方法来保存)
上述介绍的这一系列流程, 是 Cookie 在实现登录验证的时候, 涉及到的情况
# 注意 #
如果我们针对某个网站抓包, 看到的 Cookie 的情况会比上述的情况更复杂一些
比如: 现在我登录我 gitee 的个人主页, 之后将 Cookie
全部移除
此时我们打开 fidder
, 刷新个人中心页面. 此时我们发现, 登录状态已经没有了.
我们看一下响应
我们发现, 将 gitee 这里的 Cookie
删了, 重新访问, 可以看到虽然未登录, 但是服务器返回了一组 Cookie 值
正文中的内容格式和 header 中的 Content-Type 密切相关. 上面也罗列了三种常见的情况
1) application/x-www-form-urlencoded
2) multipart/form-data
3) application/json
|
以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!