Other – NaN-2 网络

网络分层模型和应用协议

分层模型

五层网络模型

面对复杂的问题,可以使用分层的方式来简化。
经过不断的演化,网络最终形成了五层模型:

Pasted image 20240803223207.png

数据的传输

发送方从上到下将信息封装,每一层往信息内加入一些信息,最终发送出去,
接收方得到信息后,从下往上一层一层解封装,得到源信息。

四层、五层、七层

Pasted image 20240803223233.png

应用层协议

URL

URL(uniform resource locator,统一资源定位符)用于定位网络服务
URL是一个固定格式的字符串

Pasted image 20240803223301.png

从网络中==哪台计算机(domain)==中的==哪个程序(port)==寻找==哪个服务(path)==,并注明了获取服务的==具体细节(path)==,以及要用什么样的==协议通信(schema)==

这里面包含了一些细节:

  • 当协议是http端口为80时,端口可以省略
  • 当协议是https端口为443时,端口可以省略
  • schema、domain、path是必填的,其他的根据具体的要求填写

URL 是 URI 的子集

HTTP

超文本传输协议(Hyper Text Transfer Protocol,HTTP)

该协议规定了两个方面的内容:

  • 传递消息的模式
  • 传递消息的格式

传递消息的模式

Pasted image 20240803223319.png

HTTP使用了一种极为简单的消息传递模式,「请求-响应」模式
发起请求的称之为客户端,接收请求并完成响应的称之为服务器。
「请求-响应」完成后,一次交互结束。

传递消息的格式

Pasted image 20240803223339.png

HTTP的消息格式是一种纯文本的格式,文本分为三个部分:

请求行
请求头

请求体

具体每一部分写什么内容,根据情况

关键信息

请求方法

请求行中的第一个单词是请求方法
在HTTP协议中,请求方法仅有语义的区别,只是表达了这次请求的「愿望」。

比如GET表达了客户端想要获取一些东西,POST表达了客户端想要提交一些东西

常见的请求方法有:

  • GET:获取
  • POST:提交
  • PUT:修改
  • DELETE:删除

通常情况下:

  • 获取数据一般使用GET
  • 提交数据一般使用POST
  • 各种静态资源的获取,一般使用GET
请求头 - Host

Host标注了URL地址中的Domain + Port

Host: levin.ink
请求头 - Content-Type

Content-Type标注了附带的请求体是什么格式
如,请求体的数据为loginId:admin, loginPwd:123456,请求体可以用不同的格式发出

Content-Type: application/x-www-form-urlencoded

loginId=admin&loginPwd=123123
Content-Type: application/json

{ "loginId": "admin", "loginPwd": "123123" }
Content-Type: multipart/form-data; boundary=aaa

--aaa
Content-Disposition: form-data; name="loginId"

admin
--aaa
Content-Disposition: form-data; name="loginPwd"

123456
--aaa
Content-Disposition: form-data; name="avatar"; filename="small.jpg"
Content-Type: image/jpeg

文件的二进制
--aaa--

x/y MINE用于描述格式
image/png, image/gif, text/plain

响应码

响应码(状态码、消息码)是响应行中的一个数字,后面往往跟上一个对应的单词,用于表达服务器对这个响应的整体「态度」

常见的响应码有:
Pasted image 20240803223402.png

常见的状态码有:

  1. 200 OK:一切正常。
  2. 301 Moved Permanently:资源已被永久重定向。
    资源地址在响应头中的Location中,浏览器会保存信息
  3. 302 Found:资源已被临时重定向。
    浏览器会缓存
  4. 304 Not Modified:文档内容未被修改。
  5. 400 Bad Request:语义有误,当前请求无法被服务器理解。
  6. 403 Forbidden:服务器拒绝执行。
  7. 404 Not Found:资源不存在。
  8. 500 Internal Server Error:服务器内部错误。
响应头 - Content-Type

Content-Type标注了附带的响应体是什么格式

常见的值有:

  1. text/plain: 普通的纯文本
  2. text/html:html文档
  3. text/javascript 或 application/javascript:js代码
  4. text/css:css代码
  5. image/jpeg:jpg图片
  6. attachment:附件
  7. 其他MIME类型

浏览器的通信能力

用户代理

浏览器可以代替用户完成http请求,代替用户解析响应结果,称之为用户代理 user agent

在网络层面浏览器拥有的两大核心能力:

  • 自动发出请求的能力
  • 自动解析响应的能力

自动发出请求的能力

当一些事情发生的时候,浏览器会代替用户自动发出http请求,常见的包括:

  1. 用户在地址栏输入了一个url地址,并按下了回车
    浏览器会自动解析URL,并发出一个GET请求,同时抛弃当前页面。
  2. 当用户点击了页面中的a元素
    浏览器会拿到a元素的href地址,并发出一个GET请求,同时抛弃当前页面。
    通常书写的地址并不是完整的url地址,浏览器会自动补全。
    通常会使用当前页面的url信息来补全缺少的信息。
当前页面 https://levin.ink/a/b/1.html
绝对路径 /a/c/2.html -> https://levin.ink/a/c/2.html
相对路径 ./3.html -> https://levin.ink/a/b/3.html
        3.html -> https://levin.ink/a/b/3.html
        ../c/4.html -> https://levin.ink/a/c/4.html
  1. 当用户点击了提交按钮<button type="submit">...</button>
    浏览器会获取按钮所在的<form>元素,拿到它的action属性地址,同时拿到它method属性值,然后把表单中的数据组织到请求体中,发出指定方法的请求,同时抛弃当前页面。
  2. 当解析HTML时遇到了<link> <img> <script> <video> <audio>等元素
    浏览器会拿到对应的地址,发出GET请求
  3. 当用户点击了刷新
    浏览器会拿到当前页面的地址,以及当前页面的请求方法,重新发一次请求,同时抛弃当前页面。

浏览器在发出请求时,会自动附带一些请求头

服务器和浏览器都有一个约定:
当发送GET请求时,不会附带请求体

由于前后端程序的默认行为,逐步造成了GET和POST的各种差异:

  1. 浏览器在发送 GET 请求时,不会附带请求体
  2. GET 请求的传递信息量有限,适合传递少量数据;POST 请求的传递信息量是没有限制的,适合传输大量数据。
  3. GET 请求只能传递 ASCII 数据,遇到非 ASCII 数据需要进行编码;POST 请求没有限制
  4. 大部分 GET 请求传递的数据都附带在 path 参数中,能够通过分享地址完整的重现页面,但同时也暴露了数据,若有敏感数据传递,不应该使用 GET 请求,至少不应该放到 path 中
  5. POST 不会被保存到浏览器的历史记录中
  6. 刷新页面时,若当前的页面是通过 POST 请求得到的,则浏览器会提示用户是否重新提交。若是 GET 请求得到的页面则没有提示。

自动解析响应的能力

浏览器不仅能发送请求,还能够针对服务器的各种响应结果做出不同的自动处理

  1. 识别响应码
    浏览器能够自动识别响应码,当出现一些特殊的响应码时浏览器会自动完成处理,比如301、302
  2. 根据响应结果做不同的处理
    浏览器能够自动分析响应头中的Content-Type,根据不同的值进行不同处理,比如:

    • text/plain: 普通的纯文本,浏览器通常会将响应体原封不动的显示到页面上
    • text/html:html文档,浏览器通常会将响应体作为页面进行渲染
    • text/javascript或application/javascript:js代码,浏览器通常会使用JS执行引擎将它解析执行
    • text/css:css代码,浏览器会将它视为样式
    • image/jpeg:浏览器会将它视为jpg图片
    • application/octet-stream:二进制数据,会触发浏览器下载功能
    • attachment:附件,会触发下载功能
      该值和其他值不同,应放到Content-Disposition头中。

基本流程

访问:https://levin.ink

Pasted image 20240803223439.png

AJAX

浏览器本身就具备网络通信的能力,但在早期,浏览器并没有把这个能力开放给JS。
最早是微软在IE浏览器中把这一能力向JS开放,让JS可以在代码中实现发送请求,并不会刷新页面,这项技术在2005年被正式命名为AJAX(Asynchronous Javascript And XML)

AJAX 就是指在web应用程序中异步向服务器发送请求。
它的实现方式有两种,XMLHttpRequest 简称XHR和Fetch
以下是两者的对比

功能点 XHR Fetch
基本的请求能力 ✅ ✅
基本的获取响应能力 ✅ ✅
监控请求进度 ✅ ❌
监控响应进度 ✅ ✅
Service Worker中是否可用 ❌ ✅
控制cookie的携带 ❌ ✅
控制重定向 ❌ ✅
请求取消 ✅ ✅
自定义referrer ❌ ✅
流 ❌ ✅
API风格 Event Promise
活跃度 停止更新 不断更新

跨域问题及解决方案

同源策略及跨域问题

同源策略是一套浏览器安全机制,当一个源的文档和脚本,与另一个源的资源进行通信时,同源策略就会对这个通信做出不同程度的限制。
简单来说,同源策略对 同源资源 放行,对 异源资源 限制
因此限制造成的开发问题,称之为跨域(异源)问题

同源和异源

源(origin) = 协议 + 域名 + 端口

例如:
http://localhost:7001/index.html的源为http://localhost:7001

两个URL地址的源完全相同,则称之为同源,否则称之为异源(跨域)

Pasted image 20240803223458.png

跨域出现的场景

跨域可能出现在三种场景:

  • 网络通信
    a元素的跳转;加载css、js、图片等;AJAX等等
  • JS API
    window.open、window.parent、iframe.contentWindow等等
  • 存储
    WebStorage、IndexedDB等等
    对于不同的跨域场景,以及每个场景中不同的跨域方式,同源策略都有不同的限制。

重点讨论网络通信中AJAX的跨域问题

网络中的跨域

当浏览器运行页面后,会发出很多的网络请求,例如CSS、JS、图片、AJAX等等
请求页面的源称之为页面源,在该页面中发出的请求称之为目标源。
当页面源和目标源一致时,则为同源请求,否则为异源请求(跨域请求)

浏览器如何限制异源请求?

浏览器制定了非常繁杂的规则来限制各种跨域请求,但总体的原则非常简单:

  • 对标签发出的跨域请求轻微限制
  • 对AJAX发出的跨域请求严厉限制

Pasted image 20240803223509.png

解决方案

CORS

CORS(Cross-Origin Resource Sharing)是最正统的跨域解决方案,同时也是浏览器推荐的解决方案。
CORS是一套规则,用于帮助浏览器判断是否校验通过。

Pasted image 20240803223524.png

CORS的基本理念是:

  • 只要服务器明确表示允许,则校验通过
  • 服务器明确拒绝或没有表示,则校验不通过
    所以,使用CORS解决跨域,必须要保证服务器是「自己人」

请求分类

CORS将请求分为两类:==简单请求==和==预检请求==。
对不同种类的请求它的规则有所区别。

简单请求

完整判定逻辑

简单来说,只要全部满足下列条件,就是简单请求:

  • 请求方法是GET、POST、HEAD之一
  • 头部字段满足CORS安全规范,详见 W3C

浏览器默认自带的头部字段都是满足安全规范的,只要开发者不改动和新增头部,就不会打破此条规则

  • 如果有Content-Type,必须是下列值中的一个
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
预检请求(preflight)

只要不是简单请求,均为预检请求

对简单请求的验证

浏览器带上一个请求头,发送到服务器,服务器只要返回表示运允许即可通过验证。
Pasted image 20240803223537.png

对预检请求的验证

  1. 发送预检请求
    先发一个预检请求,只带上请求头,包括源,请求方法,改动的请求头,服务器返回允许源,方法,请求头,预检即可通过,可以设置缓存时间。
    Pasted image 20240803223549.png

    通过后继续第二步。
  2. 发送真实请求(和简单请求一致)

细节1 - 关于cookie

默认情况下,ajax的跨域请求并不会附带cookie,这样一来,某些需要权限的操作就无法进行
不过可以通过简单的配置就可以实现附带cookie

// xhr
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

// fetch api
fetch(url, {
  credentials: "include"
})

这样一来,该跨域的ajax请求就是一个附带身份凭证的请求
当一个请求需要附带cookie时,无论它是简单请求,还是预检请求,都会在请求头中添加cookie字段
而服务器响应时,需要明确告知客户端:服务器允许这样的凭据
告知的方式也非常的简单,只需要在响应头中添加:Access-Control-Allow-Credentials: true即可
对于一个附带身份凭证的请求,若服务器没有明确告知,浏览器仍然视为跨域被拒绝。
另外要特别注意的是:对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为*。这就是为什么不推荐使用*的原因

细节2 - 关于跨域获取响应头

在跨域访问时,JS只能拿到一些最基本的响应头,如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers头让服务器把允许浏览器访问的头放入白名单,例如:

Access-Control-Expose-Headers: authorization, a, b

这样JS就能够访问指定的响应头了。

JSONP

在很久很久以前...并没有CORS方案

Pasted image 20240803223558.png

于是

Pasted image 20240803223614.png

虽然可以解决问题,但JSONP有着明显的缺陷:

  • 仅能使用GET请求
  • 容易产生安全隐患

恶意攻击者可能利用callback=恶意函数的方式实现XSS攻击

  • 容易被非法站点恶意调用
    因此,除非是某些特殊的原因,否则永远不应该使用JSONP

代理

CORS和JSONP均要求服务器是「自己人」
那如果不是呢?

Pasted image 20240803223653.png

那就找一个中间人(代理)

Pasted image 20240803223725.png

如何选择

最重要的,是要保持生产环境和开发环境一致
下面是一张决策图

Pasted image 20240803223737.png

具体的几种场景

Pasted image 20240803223748.png

Pasted image 20240803223803.png

啊哈,这里是小尾巴~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇