跨域详解

325 阅读3分钟

跨域产生的原因

  如果两个页面拥有不同的协议(protocol),端口(如果指定),或主机,那么这两个页面就属于不同一个源(origin),就会形成跨域。 而产生的原因是浏览器的同源策略,浏览器的同源策略是用于隔离潜在恶意文件的重要安全机制,这样可以使CSRF和XSS的问题得到缓解。

跨域解决方法

  • JSONP
      JSONP是JSON with padding的简写,通过<script>元素来使用,使用时可以为src属性指定一个跨域URL,<script>拥有不受限制地从其他域加载资源,因为发送的请求type是script,而不是受限制的xhr。JSONP是有效的js代码,所以在请求完成后,即在JSONP响应加载到页面之后,就会立即执行。

    eg:
    function handleResponse(response){
        console.log(reponse);
    }
    var script = document.createElement("script");
    script.src = "http://freegeoip.new/json/?callback=handleResponse";
    

    优点:简单易用,与图像ping相比,其能拿到后端返回数据
    缺点:1)JSONP是从其它域加载代码执行,如果其他域不安全,很可能会在响应中夹带一些恶意代码。
    2)要确定JSONP请求失败并不容易
    3) 服务端需要改动
    4)只支持get方法

  • CORS
      CORS 全称为 Cross Origin Resource Sharing(跨域资源共享) 先了解一个概念:
      简单请求和非简单请求
    常见的简单请求:
      请求方法为: GET POST HEAD
      请求header:
         Accept
         Accept-Language
         Content-Language
         Last-Event-ID
       content-type为以下几种:
        text/plain;multipart/form-data; application/x-www-form-urlencoded

  常见的非简单请求:
  请求方法为: PUT DELETE
  请求header:含有自定义头 content-type:json

  如果发送的是非简单请求,则浏览器会先向服务器发送一个Preflight请求(预请求),这种请求使用OPTIONS方法。返回码为204. 发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通。 Access-Control-Allow-Origin:允许请求的来源域
Access-Control-Allow-Methods:允许的方法
Access-Control-Allow-Headers:允许的头部
Access-Control-Max-Age:应该将这个Preflight请求缓存多长时间

缺点: CORS不支持IE8、IE9

  • 图像Ping
      图像Ping是与服务器进行简单、单向的跨域通信的一种方式。其得不到任何具体的数据,但可以通过侦听load和error事件,能知道响应是什么时候接收到的。
eg:
var img = new Image();
img.onload = img.onerror = function(){
    console.log('done');
}
img.src = 'http://www.example.com/test?name=ketty';

缺点: 1)只能发送Get请求
    2)无法访问服务器响应文本

  • postMessage
      方法是 HTML5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源.
      window.postMessage是一个安全的、基于事件的消息API。
      使用方法:在需要发送消息的源窗口调用postMessage方法即可发送消息。
eg:
send:
    var win = window.opener();
    win.postMessage('Hello', 'ttp://www.abc.com/');
receive:
     //为窗口注册message事件,并绑定监听函数
    window.addEventListener('message', receiveMesg, false);
    function receiveMesg(e) {
        console.log("receiveMesg: " + e.data);
    }

    注意:postMessage只能发送字符串信息。

  • ngx反向代理
      请求时还是用前端的域名,通过ngx代理将请求转发给真正的后端域名。
      代理服务器的作用:
        接受客户端请求;
        将请求转发给服务器;
        拿到服务器响应数据;
        将响应转发给客户端