• 跨域二三事


    什么是跨域?

    简单的说,没有遵守浏览器“同源政策”的操作,就是跨域。

    什么是“同源政策”?

    • 同源是说协议、域名、端口都相同。
    • 不同源下,缓存、dom获取、ajax请求都会受到限制。
    • 同源政策的目的是保护用户信息的安全,否则,cookie都共享了,用户且不是可以随意冒充了?
      但是很多时候,我们需要进行跨域操作,“同源政策”就成带来了很大的不方便,现在看看如何合理的进行跨域满足你的需要吧。

    访问缓存

    虽然说 cookie 不能跨域, 但是子域之间、子父域之间是可以共享的, 就是通过 document.domain .
    cookie共享, eg:

    // http://aa.test.com/a.html
    
    // http://bb.test.com/bb.html
    
    // 只要设置相同的主域, a.html & b.html 就可以共享cookie
    document.domain = 'test.com';
    
    // a.html
    document.cookie = "testData=helloWorld";
    
    // b.html
    var cookieYes = document.cookie;
    

    还可以在服务器设置cookie的一级域名, 这样就不用在二、三级域名下设置了. eg:
    Set-Cookie: key=value; domain=.test.com; path=/
    PS: 这种方式, 只适用于 cookie 和 iframe 的访问, localstorage 和 indexDB 都是不可以的, 需要通过 postMessage.

    Iframe

    在很久的以前, 对于不支持 XMLHttpRequest 的浏览器的最佳回溯方法之一就是使用 iframe 对象, 当然常规只是用来实现流模式的Comet.
    不得不说, 一些正常无法实现的功能/某些兼容的处理, 很多奇淫技巧都是借助 iframe 完成的.

    看看借助iframe在跨域中通信.父窗口打开 http://test1.com , iframe子窗口打开 http://test2.com.

    hash url:

    /* 父窗口给子窗口通信 */
    // test1.com
    var src = url + '#' + data;
    iframe.src = src;
    
    // test2.com 监听 hashchange
    window.onhashchange = handleChange;
    function handleChange() {
        var data = location.hash;
    }
    
    /* 子窗口给父窗口通信 */
    // test2.com
    parent.location.href = url + '#' + data;
    
    // ...
    

    window.name:

    // 子窗口 test2.com
    window.name = data;
    
    // 父窗口 test1.com
    var data = iframe.contentWindow.name;
    
    // window.name 可以携带大量信息,但是这样必须得监听子窗口 window.name 的变化
    

    window.postMessage

    不管是 hash url, 还是 window.name, 总是给人一种奇淫技巧的感觉, 有木有? 接下来的这个就不一样了, 它就是HTML5专为了解决这样问题而诞生的新朋友: 跨文档通信(Cross-document messaging)
    核心的方法就是 window.postMesage , 不管俩窗口是否同源, 都允许跨窗口通信.

    /* 窗口1 aa.com */
    var popup = window.open('http://aa.com');
    
    // 向 bb.com 发消息
    popup.postMessage("hello, bb!",
                      "http://bb.com");
    
    function receiveMessage(event) {
      // 可以过滤掉不是 bb.com 传来的消息
      if (event.origin !== "http://bb.com")
        return;
    
      // event.source is popup
      // event.data is "hi there yourself!  the secret response is: rheeeeet!"
    }
    window.addEventListener("message", receiveMessage, false);
    
    /* 窗口2 bb.com */
    function receiveMessage(event) {
      if (event.origin !== "http://aa.com")
        return;
    
      // event.source is window.opener
      // event.data is "hello, bb!"
    
      event.source.postMessage("hi there yourself!  the secret response is: rheeeeet!",
                              event.origin);
    }
    window.addEventListener("message", receiveMessage, false);
    

    这样子, localStorage 跨域也就能搞定啦.

    AJAX

    ajax 请求也是受到同源限制的, 如果我想访问第三方网站的接口怎么办呢? 目前有三个办法: jsonp / cors / websocket.

    jsonp:

    基本思路是: 通过 script.src 请求 json 数据, 约定一个回调函数名将 json 包裹获得数据

    function getScript(url) {
        var _script = document.createElement('script');
        _script.src = url;
        var body = document.getElementsByTagName("body")[0];
        body.appendChild(script);
    }
    function f(data) {
        alert(data.name);
    }
    
    getScript("http://test.com/jsonp?callback=f");
    

    jsonp 简单易用, 但是也只能发送发 get 请求.
    ps: 实际上呢, 通过 src 方式的get请求, 都是不受同源限制, 可以跨域的. 比如图片 img.src = 'test1.com'.

    CORS:

    跨域资源共享(Cross-origin resource sharing), 允许向跨域服务器发出 XMLHttpRequest 请求, 怎么做到的呢?
    基本思路: 使用自定义的HTTP头部让浏览器与服务器进行沟通, 从而决定请求或响应是成功还是失败. 所以需要客户和服务器两端支持; 对于客户端来说,感知不大, 和一般 ajax 请求似乎没有差别; 主要是对于服务端来说, 实现了 CORS 接口, 一切就ok.

    CORS的处理流程:

    • 当你使用 XMLHttpRequest 发跨域请求时, 浏览器发现该请求不符合同源策略, 会给该请求加一个请求头 Origin, 说明请求来源域.
    • 后台进行一系列处理, 如果确定接受请求则在返回结果中加入一个响应头: Access-Control-Allow-Origin, 其值为请求的 Origin 值.
    • 浏览器判断该响应头中是否包含了 Origin 的值, 如果有则浏览器会处理响应, 如果没有浏览器直接驳回请求, 这时我们无法拿到响应数据.
    • 默认只支持 GET/POST 这两种 http 请求类型, 如果要开启 PUT/DELETE 之类的, 需要在服务端在添加一个 "Access-Control-Allow-Methods" 报头标签.
    • 请求和响应都不包含 cookie 值

    IE10- 的兼容处理:

    引入 XDR(XDomainRequest), 实现安全可靠的跨域通信.

    websoket:

    websoket 是一种通信协议, 基于 TCP/IP. 它不实施同源政策, 所以基本思路是, 只要服务器设置 origin 通过, 就可以跨域

    GET /xxx HTTP/1.1
    Host: test1.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: xxxxxxxxxxxxxxxxxxxxxxx==
    Sec-WebSocket-Protocol: xxx
    Sec-WebSocket-Version: xx
    Origin: http://test2.com
    

    如果 Origin: http://test2.com 在白名单中, 就可以进行通信了.
    服务器这是会把 http 转换成 ws 协议

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: xxxxxxxxxxxxxxxxxxxxxxx==
    Sec-WebSocket-Protocol: xxx
    

    服务器代理:

    基本思想: 首先将请求发送给后台服务器, 通过服务器来发送请求, 然后将请求的结果传递给前端.

    xhr.open('POST', 'http://localhost:8888/proxy?http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer', true);
    

    参考《木的树》

    Comet

    与Web服务器通信(一)

    WebSocket

    与 Web 服务器通信(三)

    read more

    《HTTP access control》

  • 相关阅读:
    chrome输入框记住密码导致背景黄色的解决方案
    死活要居中(转载)
    Google HTML/CSS/JS代码风格指南
    CSS的inherit与auto使用分析
    photoshop中rgb与索引模式的区别
    placeholder调整颜色
    你应该了解的5个JavaScript调试技巧
    HTML TAG FROM MDN
    apple iphone 3gs 有锁机 刷机 越狱 解锁 全教程(报错3194,3014,1600,短信发不出去等问题可参考)
    史上最全的CSS hack方式一览
  • 原文地址:https://www.cnblogs.com/travelling-wxy/p/4992830.html
Copyright © 2020-2023  润新知