(二)不只是 huohuo 的 浏览器 面试题

按照网上习惯性的文章撰写路线,第二篇应该是 CSS,也确实,各种各样的标签,也是由CSS在背后默默地做属性支持。但是对于 HTML 的很多问题,跟浏览器的关系太大了,让我不禁想去好好看看 HTML 跟浏览器之间的那些事。另外,可能一提到前端,绝大多数人都会脱口而出“JavaScript”,不过我觉得 CSS 才是前端技术里最精彩绝伦的技术,所以后面我会对 CSS 做一个特殊处理,先让我先把浏览器相关面试题做一份梳理吧。

先简单认识一下什么是浏览器......

1、浏览器的主要组成部分

  • 用户界面:除了浏览器主窗口显示的请求的页面外,其他显示的各个部分都属于用户界面。
  • 浏览器引擎在用户界面和呈现引擎之间传送指令。
  • 呈现引擎: 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML CSS 内容,并将解析后的内容显示在屏幕上。
  • 网络:用于网络调用(如 HTTP 请求)。其接口与平台⽆关,并为所有平台提供底层实现。
  • 用户界⾯后端:用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台⽆关的通用接口,而在底层使用操作系统的⽤户界面方法。
  • JavaScript 解释器:用于解析和执行 JavaScript 代码。
  • 数据存储:这是持久层。浏览器需要在硬盘上保存各种数据(如 Cookie)HTML5 定义了络数据库”,这是⼀个完整(轻便)的浏览器内数据库。Chrome 浏览器的每个标签⻚都是⼀个独立的进程。

2、浏览器内核

什么是浏览器内核

浏览器内核作为浏览器最核心的部分 “Rendering Engine”,也就是渲染引擎,它决定了浏览器如何解析网页语法并渲染网页内容。

常见的浏览器内核

浏览器 /RunTime
内核(渲染引擎)
JavaScript 引擎
Chrome
Blink 28~
Webkit Chrome 27
V8
FireFox
Gecko
SpiderMonkey
Safari
Webkit
JavaScriptCore
Edge
EdgeHTML
Chakra(for JavaScript)
IE
Trident
Chakra(for JScript)
PhantomJS
WebkitJavaScriptCore
Node.js-V8

上面其实做个简单的了解就可以了,接下来是关于浏览器我觉得最精彩的一个问题,其中又包含了多个经典的面试题。在以前的文章我有做过总结,这里我再次梳理一下。

3、从浏览器输入一个url到显示页面经历的过程

这个过程其实就是一次完整的 http(1.0) 请求过程:

  1. 浏览器对输入的网址进行DNS解析,得到对应的IP地址
  2. 根据这个IP,找到对应的服务器,发起TCP连接(TCP的三次握手)
  3. 建立TCP链接后,发起HTTP请求
  4. 服务器响应HTTP请求,浏览器得到 html 代码
  5. 浏览器解析 html 代码,再请求代码中的资源(js、css、图片等)
  6. 浏览器渲染页面
  7. 服务器断开TCP连接(TCP的四次挥手)

整个过程清晰可见,让我们开始逐个击破吧 ~~~

URL是啥?

URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上资源,俗称网址。

看一下它的定义规则:

scheme://host.domain:port/path/filename

各部分解释如下:

  • scheme:定义因特网服务的类型。常见的协议有 http、https、ftp、file,其中最常见的类型是 http,而 https 则是进行加密的网络传输。
  • host:定义域主机(http 的默认主机是 www)
  • domain:定义因特网域名,比如 w3school.com.cn
  • port:定义主机上的端口号(http 的默认端口号是 80)
  • path:定义服务器上的路径(如果省略,则文档必须位于网站的根目录中)。
  • filename:定义文档/资源的名称

DNS怎么找到域名的?

我们先看几个小概念

  • DNS:一个网络服务器
  • DNS 协议:提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务
  • DNS域名解析:即在 DNS 上记录一条信息记录(域名对应的 IP 地址)

那浏览器如何通过域名去查询 URL 对应的 IP 呢?

过程(面试):浏览器自身域名缓存区找 =》操作系统的域名缓存区找 =》hosts文件找 =》域名服务器找

为什么HTTP协议要基于TCP来实现?

TCP是一个端到端的可靠的面相连接的协议,HTTP基于传输层TCP协议,不用担心数据传输的各种问题(当发生错误时,会重传)

浏览器是如何渲染页面的?

  1. 构建DOM树:渲染引擎解析HTML文档,将标签转换成DOM节点构建DOM树
  2. 生成渲染树:解析CSS文件(生成CSS规则树),再生成渲染树,使每个节点有自己的样式
  3. 布局渲染树:从根节点递归调用,布局出每个节点的位置、尺寸(布局)
  4. 绘制渲染树:遍历渲染树,使用UI层绘制每个节点 ,呈现界面

既然涉及到了布局和渲染,那怎么能少了重绘和回流呢 ~~~

4、对重绘和回流的了解

概念

  • 重绘:元素外观(如背景颜色)改变引起的浏览器行为,使元素外观重新绘制
  • 回流(重排):渲染树中的元素布局或几何属性(如尺寸、隐藏)等改变,需要重新构建

注意点

  • 每个页面至少发生一次回流,即页面第一次加载的时候
  • 回流必定引发重绘,重绘不一定引发回流

补充

触发回流的条件:任何页面布局或几何属性的改变

  • 页面渲染初始化(无法避免)
  • 添加或删除可见的DOM元素
  • 元素位置的改变,或使用动画
  • 元素尺寸的改变(大小,外边距,边框)
  • 浏览器窗口尺寸的变化(resize事件)
  • 填充内容的改变(文本或图片大小改变,引起计算值宽高改变)
  • 读取某些元素属性(offsetLeft/Top/Height/Width, clientLeft/Top/Height/Width,scrollLeft/Top/Height/Width等)

如何优化?

重绘回流会造成耗时、浏览器卡顿,那么如何做优化呢?(尽量减少DOM操作)

  • 浏览器优化:浏览器会把引起回流、重绘的操作放入一个队列,等队列中的操作到了一定数量或者时间间隔,就 flush 这个队列进行一个批处理。这样就可以让多次回流重绘变成一次。
  • 代码优化:减少对渲染树的操作,可以合并多次 DOM 和样式的修改,并减少对样式的请求。

一些代码优化操作举例:

  • 修改元素样式的时候,直接修改样式名className(尽量一次修改元素样式,不要一会改一点。也就是把新样式放在另一个样式名中)
  • 某些元素先设置成display: none,然后进行页面布局操作,再设置display: block(这样只会引发两次重绘回流)
  • 使用cloneNode和repalceChild技术(引发一次重绘回流)
  • 将需要多次回流的元素,position属性设为absoluted或fixed(元素脱离文档流,变化不会影响其他元素)
  • 当需要创建多个节点的时候,使用DocumentFragment创建完后一次性的加入(如循环创建一个li,让循环结束后所有的li都创建完了(fragment中)再一次性加入(文档))

顺利完成了一次资源的请求,我们浏览器拿到了服务器发送过来的资源,为了节省性能,当然少不了存储了,那么请列出你所知道的浏览器的一些存储办法以及它们的区别吧 ~

5、cookie,session,storage的区别

这一块以前做过一张还不错的表,这里附上,并做了一些改进。

本地存储区别表

WebStorage(HTML5)
cookiesession(服务器)sessionstoragelocalstorage
数据生命周期一般由服务器生成,在设置失效时间(expires)内有效(与窗口或浏览器是否关闭无关)。若在浏览器设置,默认浏览器关闭后失效除非被清除,否则永久保存(刷新页面数据依旧存在)仅在当前会话有效,关闭窗口或浏览器后清除除非web应用主动删除,否则永不失效
存放数据4kb左右,数量最多20条,存储字符串5M,存储对象5M,只能存储字符串
与服务端通信保存在浏览器端。每次都会携带在HTTP请求头中,参与服务器通信保存在服务器端,不参与服务器通信。会占用服务器性能保存在客户端(本地存储),不参与服务器通信
安全性安全性较低(cookie诈骗cookie截取)session安全性大于cookie
易用性一般接口需要自己封装接口可以直接使用
作用域在浏览器所有的同源窗口中共享不能在不同的浏览器窗口共享不能在不同的浏览器窗口共享,在同源窗口中可以共享
使用场景

主要用于保存登录信息

1、判断用户是否登录过网站,方便下次登录实现自动登录或记住密码

2、上次登录的时间等信息

3、上次查看的页面

4、浏览计数

用于保存每个用户的专用信息,变量的值保存在服务器端,通过sessionID来区分不同用户。

1、购物车

2、用户登录信息

3、将某些数据放入session中,供同一用户的不同页面使用

4、防止用户非法登录

敏感账号一次性登录、表单,对于那种只需要在用户浏览一组页面期间保存而关闭浏览器后就可以丢弃的数据,sessionStorage会非常方便

常用于长期登录(判断用户是否登录),适合长期保存在本地的数据。

购物车信息、HTML5游戏产生的一些本地数据

优点具有极高的扩展性和可用性

1、存储空间大

2、节省网络流量

3、可在本地直接获取,不需要与服务器交互

4、获取速度快

5、安全性较高

6、更多丰富易用的API接口

7、支持事件通知机制,可以将数据更新的通知发送给监听者

8、操作方便:setItem、getItem、removeItem、clear、key、length

9、临时存储

缺点

1、大小受限

2、用户可以禁用cookie,使功能受限

3、安全性较低

4、有些状态不能保存在客户端

5、同源请求时会被携带(服务端和客户端互传,不论是否需要),加大http流量,数据过多影响性能

6、cookie数据有路径(path)的概念,可以限制cookie只属于某个路径下

对浏览器的存储方式有了清晰的了解以后,我们应该再思考,存下的数据如何使用会性能更好?存下的数据我们是否需要做适时的更新?浏览器底层有什么特别的机制?

6、浏览器缓存策略

面试的时候,少不了关于性能优化的问题,基于上一个问题,不难想到浏览器端应该做的一个优化手段 ==> 减少 HTTP 请求。为此我们可以做 HTTP 缓存控制,也就是浏览器缓存策略。

关于浏览器缓存的初步回答

  1. 浏览器(HTTP)缓存能够帮助服务器提高并发性能,很多资源不需要重复请求,可直接从浏览器中拿缓存(通过 HTTP 获取的资源)
  2. 浏览器缓存分类:强缓存、协商缓存
  3. 强缓存通过 Expires 和 Cache-control 控制,协商缓存通过 Last-modify 和 Etag 控制

这是一个比较笼统的回答,不过我觉得十分的精辟且可聊性较高。因为它引出了三个重要的问题:浏览器的缓存策略、缓存分类及缓存访问。

浏览器缓存策略(机制)

缓存策略主要发生在三个对象之间:浏览器、浏览器缓存、服务器

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识

  • 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中

我们根据请求结果和缓存标识来判断是否需要向服务器重新发起 HTTP 请求,而这个过程我们使用的缓存策略也不相同。

缓存策略都是通过设置 HTTP Header 来实现的,基于此我们把浏览器缓存分为强缓存和协商缓存。这两个缓存其实就是浏览器做缓存时的不同处理过程。

强缓存

不会向服务器发送请求,直接从浏览器缓存中读取资源

 HTTP Header 实现: 和 Cache-Control

  • Expires(http1.0):缓存过期时间(绝对时间),用来指定资源到期的时间,是服务器端的具体的时间点(在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求)。受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
  • Cache-Control(http1.1):是一个相对时间,代表资源的有效期。(优先) 

现在基本上都会同时设置 Expires 和 Cache-Control

强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存。

协商缓存

强缓存未命中,浏览器携带缓存标识向服务器发起请求由服务器根据缓存标识决定是否使用缓存的过程(判断该标识对应的资源是否更新)

看看协商缓存的结果情况:

  • 协商缓存生效,返回 304 和 Not Modified,告诉浏览器使用本地缓存
  • 协商缓存失效,返回 200 和 请求结果(新资源),并存入缓存

强缓存未命中,是什么时候才未命中呢?协商缓存,协商的是什么呢?        

其实就是:浏览器问服务器,我缓存的资源有没有更新啊?

  • 没有更新:浏览器可以用缓存(304)
  • 更新了:浏览器不能用缓存,服务器发新的给浏览器(200)

HTTP Header 实现:Last-Modified 和 ETag (帮助浏览器跟服务器进行协商)

  • Last-Modified:浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间 。当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。如果命中缓存,则返回http304,并且不会返回资源内容,并且不会返回Last-Modify。由于对比的服务端时间,所以客户端与服务端时间差距不会导致问题。但是有时候通过最后修改时间来判断资源是否修改还是不太准确(Last-Modified 只能以秒计时)。于是出现了ETag/If-None-Match,根据资源内容是否修改来决定缓存策略。
  • Etag(http1.1):服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),Etag/If-None-Match返回的是一个校验码 。ETag可以保证每一个资源是唯一的,只要资源有变化,Etag就会重新生成。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。

HTTP1.1中 Etag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:

  • Last-Modified标注的最后修改只能精确到秒,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
  • 如果某些文件会被定期生成或者改完又改回来,内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存
  • 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

可能面试官会问你,Last-Modified 与 ETag 哪个更好呢?

  • 精度上:Last-Modified 单位是秒,ETag 单位是每次, ETag精确度更优
  • 性能上:Last-Modified 只需要记录时间,而 Etag 需要服务器通过算法来计算出一个hash值。故 Last-Modified 性能更好 
  • 优先级:服务器校验优先考虑 Etag

关于优先级的补充:Etag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回304。

缓存访问

这个过程我们针对强缓存和协商缓存进行讨论(借用大佬的图片)

强缓存优先于协商缓存进行,若强缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。

唔 ~ 终于理完了,太不容易了。面试的时候能说到这里已经很牛了哇,但是调皮的面试官可能还会问一个比较细的问题。 emmmm......

如果什么缓存策略都没设置,那么浏览器会怎么处理?

对于这种情况,浏览器会采用一个启发式的算法,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。

其他

实际应用场景

  • 频繁变动的资源
  • 不常变化的资源

用户行为对浏览器缓存的影响

新开窗口有效有效
用户操作Expires/Cache-ControlLast-Modified/Etag
地址栏回车有效有效
页面链接跳转有效有效
前进、后退有效有效
F5 刷新无效有效
Ctrl+F5 刷新无效无效

说到浏览器的策略,除了缓存策略,我们不得不提的就是浏览器同源策略了 ~~

7、浏览器同源策略

同源

源:

  • 协议
  • 域名
  • 端口

同源即协议、域名和端口都相同。

什么是同源策略

浏览器的同源策略是一种安全功能,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的安全机制(不同源之间,不能进行交互)

如 google.com下的 js脚本采用 ajax 读取 baidu.com里面的文件数据是会报错的。

既然说到 ajax ,脑海里不禁涌现出一个又爱又恨的面试题了哈哈哈哈,敲了这么多文字,动手来点代码疏通下筋骨吧。

来,给我手写一个原生 ajax ~~~ (嘘,简单的就行啦!)

        var xhr = new XMLHttpRequest(); // 创建 Ajax 对象
        xhr.open('get', 'https://blog.youkuaiyun.com/huohuoit'); // 告诉 Ajax 请求地址以及请求方式
        xhr.send(); // 发送请求数据
        xhr.onreadystatechange = function () { // 获取服务器端给与客户端的响应数据
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);
            }
        }

        // 啊 ~~~ 报错啦!~~~

限制问题

浏览器中的大部分内容都是受同源策略限制的,如:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求发送后,结果被浏览器拦截了
  • 一些第三方插件如 FLASH

但是有一些资源时不受同源策略限制的:

  • 页面中的链接,重定向以及表单提交
  • <script>、<img>、<iframe>、<link>、<video> 等标签

在浏览器中,<script>、<img> 、<iframe>、<link>、<video> 等标签都可以跨域加载资源,而不受同源策略的限制,通过 src 属性加载的资源,浏览器都会发起一个 GET 请求,但是浏览器限制了 JavaScript 的权限,使用 js 不能读、写加载的内容。

你可以通过这几个标签来跨域加载资源,但是,发起的GET请求返回的数据,通过 js 获取不到。

注意:通过 <script> 标签获取 js 文件里的全局属性,方法等,可以通过 js 读取到。是因为这些都是挂载在 window对象上的。

上面我们提到了跨域,相信你经常会在面试题上看到这个问题,那就顺着上文开始跟我一起拿下它吧。

8、跨域

什么是跨域

什么是跨域呢?我们上面提到了同源,同源中有“三个同”,其中一个就是“域”,但是这里的域不是这个域哈,这里的域是指“源”,也即域名地址。

上面我们讨论到,浏览器同源策略下,会引起不同源之间不能进行交互的问题。那么跨域其实就是解决不同源之间请求发送数据、通信等交互问题的解决方法。

我们知道,发生跨域的时候,是会发送请求的,但是可能拿不到跨域的资源,那么这个请求是否真的发出去了呢?

事实是,跨域请求能发出去,服务端也能收到请求并正常返回结果,只是结果被浏览器拦截了。

在上一个同源策略问题中,我们提到了一些是否受同源策略限制的情况。可以看到,通过表单提交的方式是可以发起跨域请求的,而 AJAX 却不可以。

归根结底,跨域是为了阻止用户读取到另一个域名下的内容。表单提交并不会获取新的内容,所以可以发起跨域请求;而 AJAX 是可以获取到响应内容的,浏览器会判定为不安全,所以会拦截响应的内容。

note:这个问题说明跨域并不能完全阻止 CSRF,因为请求已经发送出去了。

跨域的实现

跨域的实现一般都是后端作处理,针对面试,我们前端只需要了解一些典型的方案即可。

jsonp 跨域(最经典的跨域方案)

哦豁?json?jsonp?两者其实没啥关系,只是 jsonp 请求后得到的是 json 数据格式

我们可以更详细一点:

  • jsonp 是 JSON With Padding(填充式 json 或参数式 json )的简写
  • 组成(两部分):回调函数  数据。回调函数是用来处理服务器端返回的数据,回调函数的名字一般是在请求中指定的。而数据就是我们需要获取的数据,也就是服务器端的数据。

jsonp 实现跨域的请求原理

动态创建<script>标签,然后利用<script>的 src 属性不受同源策略约束来跨域获取数据。

你可能会跟我一样疑惑,为什么是 <script> 标签?

在上一个问题的最后,我们说到 <script>、<img>、<iframe>、<link>、<video>等标签可以跨域加载资源,但是为啥只有 <script>标签可以请求到数据呢。

<script> 在请求得到数据后,遇到 js 代码,就会解析执行( js 文件里写的代码肯定要被执行的)

jsonp 的 优点:
  • 实现简单
  • 兼容性⾮常好
jsonp  的缺点:*
  • 只⽀持 get 请求(因为 <script> 标签只能get
  • 有安全性问题,容易遭受 XSS 攻击(注入恶意代码,篡改页面内容,可以采用字符串过滤来规避此问题
  • 需要服务端配合 jsonp 进⾏⼀定程度的改造

jsonp 的实现(了解即可):

        function JSONP({ url, params, callbackKey, callback }) {// 在参数⾥制定 callback 的名字 
            params = params || {};
            params[callbackKey] = 'jsonpCallback'; // 预留 callback 
            window.jsonpCallback = callback; // 拼接参数字符串 
            const paramKeys = Object.keys(params);
            const paramString = paramKeys.map(key => `${key}=${params[key]}`).join('&');
            // 插⼊ DOM 元素 
            const script = document.createElement('script');
            script.setAttribute('src', `${url}?${paramString}`);
            document.body.appendChild(script);
        }
        JSONP({
            url: 'https://blog.youkuaiyun.com/huohuoit',
            params: {
                key: 'test',
            },
            callbackKey: '_cb',
            callback(result) {
                console.log(result.data)
            }
        });

千万要记住:JSONP 要借助服务端的支持哦!

CORS 跨域(最流行的跨域方案)

CORS(Cross-Origin Resource Sharing,跨源资源共享)定义了在访问跨源资源时,浏览器与服务器应该如何沟通。

机制原理:它使⽤额外的 HTTP 头来告诉浏览器 让运⾏在⼀ 个 origin (domain) 上的Web应⽤被准许访问来⾃不同源服务器上的指定的资源。当⼀个资源从与该资源本身所在的服 务器不同的域、协议或端⼝请求⼀个资源时,资源会发起⼀个跨域 HTTP 请求。

CORS 需要浏览器和后端同时支持

浏览器会自动进行 CORS 通信,而实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。

这一块可以看看阮一峰老师的:跨域资源共享 CORS 详解

如果你用node 的 express ,可以在后端做如下配置

        //CORS middleware 
        var allowCrossDomain = function (req, res, next) {
            res.header('Access-Control-Allow-Origin', 'http://example.com');
            res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
            res.header('Access-Control-Allow-Headers', 'Content-Type'); next();
        }//... 
        app.configure(function () {
            app.use(express.bodyParser());
            app.use(express.cookieParser());
            app.use(express.session({ secret: 'huohuoit' }));
            app.use(express.methodOverride());
            app.use(allowCrossDomain);
            app.use(app.router);
            app.use(express.static(__dirname + '/public'));
        });

Nginx 跨域(最简单方便的跨域方案)

实现原理:

  • 同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略
  • 所有客户端的请求都必须先经过nginx的处理, nginx 作为代理服务器再讲请求转发给 node
    java 服务,这样就 规避了同源策略。

代理服务器,需要做以下几个步骤:

  • 接受客户端请求 。
  • 将请求转发给服务器。
  • 拿到服务器响应数据。
  • 将响应转发给客户端。

实现思路:搭建一个中转Nginx服务器,用于转发请求,作反向代理实现跨域,只需要修改 Nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。

这一块网上有很多优秀的教程,大家可以自行搜索学习哈!!!

其他跨域方案

  1.  HTML5 XMLHttpRequest 有⼀个APIpostMessage()⽅法允许来⾃不同源的脚本采⽤异步⽅式进⾏有限的通信,可以实现跨⽂本档、多窗⼝、跨域消息传递。
  2.  WebSocket:是⼀种双向通信协议,在建⽴连接之后,WebSocket server client 都能主动向对⽅发送或接收数据,连接建⽴好了之后 client server 之间的双向通信就与 HTTP ⽆关了,因此可以跨域。
  3.  window.name + iframewindow.name属性值在不同的⻚⾯(甚⾄不同域名)加载后依旧存在,并且可以⽀持⾮常⻓的 name 值,我们可以利⽤这个特点进⾏跨域。
  4.  location.hash + iframea.html欲与c.html跨域相互通信,通过中间⻚b.html来实现。 三个⻚⾯,不同域之间利⽤ iframelocation.hash传值,相同域之间直接js访问来通信。
  5. document.domain + iframe该⽅式只能⽤于⼆级域名相同的情况下,⽐如 a.test.com b.test.com 适⽤于该⽅ 式,我们只需要给⻚⾯添加 document.domain ='test.com' 表示⼆级域名都相同就可以实现跨域,两个⻚⾯都通过 js 强制设置document.domain为基础主域,就实现了同域。

以下内容是后面添加的有关web服务器的内容,服务器相关内容在前端部分可能不会涉及太多,个人实力有限,暂时无法开一篇专题出来。所以就放在浏览器的末尾啦!以下内容我觉得挺重要的,也有不少知识点在上文提到过,可能对大家的理解更有帮助哈 ~

WEB服务器

这里我主要关心服务器的作用:一台服务器可以作为源服务器,也可以作为中转服务器,甚至可以在一台服务器上搭建多个不同域名的网站。

虚拟主机

HTTP/1.1规范允许一台HTTP服务器搭建多个Web站点。利用虚拟主机的功能,可以在一台物理服务器(一个IP地址)上虚拟出多个主机,每个主机映射一个独立的域名。因此,当用户访问域名http://huohuoit.com 时,DNS域名系统会将其解析成IP地址,根据IP找到物理服务器,然后再通过请求首部的HOST字段(HTTP/1.1要求必带)确认对应的虚拟主机。

代理服务器

代理服务器就是客户端和服务端之间的“中间商”,即HTTP请求通过代理服务器转发给服务器,再将服务器的响应返回给客户端的行为。代理服务器可以用来作为缓存服务器,也可以用来隐藏用户身份(正向代理)或者服务器身份(反向代理)增加安全性。

  • 正向代理:是客户端为了从源服务器中取得内容,由客户端向代理服务器发出请求,并指定目标访问服务器,然后,代理服务器向源服务器转交请求,并将获得的内容返回给客户端。隐藏了真实请求的客户端,即服务端不知道正式请求客户是谁。(科学上网)

  • 反向代理:是由客户端向代理服务器发出请求,代理服务器收到请求后判断请求方向,然后再将请求结果反回给客户端。隐藏了源服务器的信息,用户不需要知道是具体哪一台服务器提供的服务,只要知道反向代理服务器是谁。(实现负载均衡,Nginx)

  • 反向代理解决跨域问题:例如在使用 vue-cli 这种脚手架工具进行开发时,经常会遇到跨域的问题,因为项目自身启动本地服务是需要占用一个端口(如 http://localhost:8080)的,所以必然会产生跨域的问题(因为本地服务端口和服务端接口地址不同源)。出现跨域是因为浏览器有同源策略的限制,但服务器是没有的同源策略的限制的。当我们本地服务(http://localhost:8080)要请求目标服务器(http://huohuoit.com)的资源的时候,我们不直接请求 http://huohuoit.com,而是请求本地服务自身 http://localhost:8080 (这时是同源请求,不存在跨域),本地代理服务再将接口转发给 http:huohuoit.com (注意这时候是两个服务器直接的通信了,所以更不存在跨域),本地服务获取到目标服务器的响应数据之后通过再代理伪装成本地服务请求的返回值返回给客户端。

我们梳理一下反向代理解决跨域问题的流程:

本地服务在浏览器向本地服务发起请求 --> 本地代理转发 --> 目标服务器 --> 响应数据后通过代理伪装成本地服务器请求的返回值 --> 浏览器接受到目标服务器的数据

如果你有兴趣的话,这里再给出一个 vue-cli 反向代理配置:

//vue.config.js

  devServer: {
    port: 8080, // 配置端口
    open: true, // 项目启动自动开启浏览器
    compress: true, // 开启压缩
    overlay: { // 设置让浏览器 overlay 同时显示警告和错误
      warnings: true,
      errors: true
    },
    // 设置请求反向代理
    proxy: {
      '/api': { // 要代理的接口的匹配字符
        target: process.env.BASE_URL, // 接口域名
        secure: false,
        changeOrigin: true
      }
    }
  },

需要注意如果要用反向代理,则在 axios 配置的时候,请求 baseURL 必须设置为字符串 '/' ,否则 proxy 会匹配不到 '/api' 导致代理失败。

缓存服务器

缓存服务器指的是将需要频繁访问的网络内容存放在离用户较近、访问速度更快的服务器中,以提高内容访问速度的一种技术。缓存服务器是浏览器和源服务器之间的中间服务器,浏览器先向这个中间服务器发起HTTP请求,经过处理后(比如权限验证,缓存匹配等),再将请求转发到源服务器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值