同源&跨域

281 阅读2分钟

同源策略

如果两个 URL 的协议端口域名都完全一致的话,则这两个 URL 是同源的。

跨域

如果协议域名或者端口有一个不同就是跨域,Ajax 请求会失败。

实现跨域的方式

jsonp

Edit jsonp

  • JSONP 使用简单且兼容性不错,但是只限于 get 请求
  • 不安全, 不建议使用
  • JSONP 的原理很简单,就是利用
// 注意: 要先定义函数,再添加<script>标签
<script>
    function jsonp(data) {
    	console.log(data)
	}
</script>   
<script src="http://domain/api?param1=a&param2=b&callback=jsonp"></script>
// 在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP,以下是简单实现

function jsonp({url, params, cb}) {
    return new Promise((resolve, reject) => {
        //  @ 1 : 定义 call back 函数
        window[cb] = function (data) {
            resolve(data)
            document.body.removeChild(script)
        }

        //  @ 2 : 设置url参数  'https://www.sdf.com' ---> 'https://www.sdf.com?wd=a&cb=callback'
        url = `${url}?${stringify(params)}&cb=${cb}`

        //  @ 3 : 添加 script 标签
        let script = document.createElement("script")
        script.src = url
        document.body.appendChild(script) // script标签将会调用window[cb]函数
    })
}

function stringify(params) {
  let list = []
  for(let key in params) {
    list.push(`${key}=${params[key]}`)
  }
  return list.join('&')
}

// 使用

jsonp({
    url: 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',     // ------>> 这是百度搜索的接口
    params: {wd: "b"},
    cb: 'show'
})
.then(res => console.log(res))
    

CORS

  • CORS, 就是让后台设置一个白名单, 白名单里的网站可以跨域
  • 实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
  • CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。

nginx

websokit

postMessage

  • 网站a的client无法直接获取网站b的server的数据
  • 网站b的client可以直接获取网站b的server的数据
  • 可以用<iframe>网站b的client嵌入到网站a的client
  • 此时两个client页面可以实现通信
  • 那么网站b的页面就可以将它获取到的所有后台数据发送给网站a的页面

网站A的页面

<body>
    <iframe src="https://bbb.com" frameborder='0' id="iframe" onload="load()"></iframe>
    <script>
        function load() {
            let iframe = document.getElementById('iframe')
            iframe.contentWindow.postMessage('把数据给我', "https://bbb.com")    // 页面A向页面B发送消息
            window.onmessage = function(e) {
                console.log('获取到的数据为', e.data)
            } // 页面A接收页消息
        }
    </script>
</body>

网站B的页面

<script>
    window.onmessage = function(e) {
        console.log(e.data)
        e.source.postMessage('info', e.origin)
    }   // 页面B接收消息, 并将info放送出去
</script>

document.domain

该方式只能用于二级域名相同的情况下,比如 a.test.comb.test.com 适用于该方式。

只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域