2

前言

唔,面试的时候被问到了,然后把之前自己知道的情况都说了一下,但是后面还是感觉这其中还是有很多细节可以继续扒,所以这里来小结一下,为什么是挖坑系列,因为我一次性肯定写不完,算是经历了此次几轮面试后的一个学习小结的开始吧。(如果有错误,欢迎提出)

什么是跨域问题?

之前看了很多文章,都没有很系统/官方的一个定义。这里选了一个比较靠谱的说法:

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。

而我们通常说的问题来源于js发起的ajax请求、dom和js对象的跨域操作等。

浏览器同源政策

也就是协议域名端口号一致,浏览器才会承认它们之间是不会存在跨域的限制。

注意www.a.baidu.comwww.b.baidu.com这种二级域名不一样也是相当于域名不相同的)

常见限制如下

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 和 Js对象无法获得
  3. AJAX 请求不能发送

为什么要进行限制?
浏览器为了能够减少网络安全攻击问题采取的。
比如你直接在某个网站嵌入一段代码,其中获取了document.cookie,然后通过一个请求发送给你的网站,这样就可以盗取别人的cookie信息。

实践提问区

Q:如果发送一个Ajax请求发生跨域,浏览器会做出什么反应呢?
我们来做一个页面A:localhost/ajax:

   function get() {
         var xhr = new XMLHttpRequest();
         xhr.open("get","http://127.0.0.1/ajax/data.json",true);
         xhr.onreadystatechange = function() {
           if(xhr.readyState == 4) {
               if(xhr.status == 200 || xhr.status == 304) {
                alert(xhr.resonseText);
               } else {
                   alert("请求失败啦");
               }
           }
         }
         xhr.send(null);
   }

在页面A中请求:127.0.0.1/ajax/data.json
(没错,localhost和127.0.0.1两个家伙其实是同一个页面(。・∀・)ノ,但是它们的域名并不一样)
运行这个函数去请求之后,浏览器报错啦!
图片描述
图片描述

Failed to load http://127.0.0.1/ajax/data.json: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

可以看到,它说因为没有Access-Control-Allow-Origin出现在请求资源的头部信息中,所以不允许http://localhost通行。(这是不是也暗示了我们,其中一种解决方法呢)

Q:浏览器发送了请求吗?它有没有收到什么回应?
之前不是说浏览器限制我们的发送吗?所以它发送了请求吗?打开控制台发现,它不仅发了一个data.json请求,格式为xhr,状态码是200。
图片描述
瞅瞅下面这个报文的具体请求信息:
图片描述

再瞅瞅这个报文的Response:
图片描述

唔,会发现它其实收到了这个回应呢。

Q:更换请求方式,情况会发生改变吗?
我把请求方式从GET改成PUT,再去发送请求,除了和之前的弹错误警告框,控制台报错一样外,报文如下:
图片描述

可以发现它的请求方式变成了OPTIONS,且response是空。

简单/复杂请求

为什么用PUT请求后,请求的方式变成了OPTIONS呢?这就涉及简单/复杂请求的问题了。
简单请求的条件

  1. 必须是HEADGETPOST中的其中一种请求方法。
  2. 请求头选项只能有如下几个:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type
  3. Content-Type只能是以下之一:application/x-www-form-urlencodedmultipart/form-datatext/plain

当然啦,如果不是简单请求,自然就是复杂请求了。

区别:
复杂请求会先发送一种"预请求",服务端也会返回"预回应"作为响应。只有预请求成功返回,实际的请求才会继续发送,预请求以OPTIONS方法发送,所以可以看到之前那个PUT方法的报文是OPTIONS

Q:我有一个疑问,它控制台报错说是不允许客户端的请求,如果服务器端允许客户端域名进行请求的话,那发送就可以带上了请求,如果是这样的话,那也不能保护客户端的cookie安全啊0_0?

其他测验

localStorage

我们依旧在页面A:localhost/ajax,先写好一个设置localStorage的函数:

   function setStorage() {
        if(window.localStorage) {
            localStorage.setItem("text","你好");
        } else {
            new Error("不支持LocalStorage");
        }
   }

我们再写一个获取localStorage的函数:

       function getStorage() {
            if(window.localStorage) {
                console.log(localStorage.getItem("text"));
            } else {
                new Error("不支持LocalStorage");
            }           
       }

我们在localhost下点击设置,去127.0.0.1下面尝试获取,会发现结果是null。但是如果回到localhost页面,会发现出现了“你好”。另外我又在该目录下增加了一个页面,以localhost打开会发现它也能取到这个“你好”,因为它们是同源的所有没有这个限制。

Cookie相关

我们先预先来剧透一下,暂时用jQuery的封装发送一个jsonp请求来实现跨域,再来看看请求的差别:

$.ajax({
    url: "http://127.0.0.1/ajax/data.json?callback=showData",
    type: "GET",
    dataType: "jsonp",
    jsonpCallback: "showData",
    success: function(data) {
            showData();
    }
}) 

发送请求的报文如下:
图片描述

和最开始没有解决跨域的请求相比,多了Cookie值:
图片描述

所以可以认为,浏览器在没有解决跨域问题之前,不会把Cookie带上去。

iframe

在页面里嵌入一个iframe标签,它也会产生这个问题吗,于是我们在localhost/ajax/index.php下又嵌了一个localhost/ajax/index.php,在iframe里面去点击向127.0.0.1/ajax/index.php发送请求,结果报错了,说明它是存在这个限制的。

解决方法

可以说解决方法是烂大街了哈哈哈~

JSONP

XHR请求存在跨域限制,但是script并不存在,利用这个特点,我们就出现了JSONP来解决跨域。

Nginx反向代理

Q:什么叫做反向代理?
我们都明确代理的意思,就是“帮你做事情的人”。因为浏览器存在同源政策,无法进行跨域,但是服务器之间没有这样的约束,所以我们就设置这样一个代理机关,让客户误以为可以请求,实际上是转交了。
也就是说反向代理,代理的是服务器的角色。类似的情况还有对客户端的访问进行一个就近分配(CDN),或者分散流量等。

Q:那你知道正向代理吗?
有反向代理,肯定有正向代理,而且就是方向反了。正向代理代理的是服务器,为什么它是正的?因为在很多年前,我们从局域网访问外网,其实就是通过代理去访问的,这时候代理代替了我们,比如我们使用VPN进行绿色上网。

postMessage


MOCHIKO
318 声望29 粉丝