饥人谷技术博客前端开发技术

跨域的几种实现方式

2019-05-24  本文已影响87人  fanlelee

一、背景

同源策略

同源策略可以理解为浏览器的一种安全机制,浏览器只允许与本域下的接口进行交互。不同源的客户端在没有明确授权的情况下,不能读写服务端的资源。

什么是不同源呢:
补充点

在出现跨域问题时,浏览器究竟在哪一步进行了拦截?客户端请求时?服务器不做出响应?还是服务器响应后浏览器拒绝的响应??


image.png
image.png

测试发现,在客户端和服务端不同源的情况下,服务端其实是有响应的,在此时是浏览器的同源策略拒绝了响应,认为这样不安全。

二、解决跨域问题

1. JSONP(JSON with Padding)

<body>
    <button class="btn">获取天气</button>
</body>
<script>
    function weather(data){
        console.log(data)
    }
    document.querySelector('.btn').addEventListener('click', function(){
        var script = document.createElement('script')
        script.src = 'http://localhost:8080/getWeather?callback=weather&a=b'
        document.head.appendChild(script)
        document.head.removeChild(script)
    })
</script>

服务端:

    '/getWeather':function(req, resp){
        resp.writeHead(200, 'success')
        if(req.query.callback){
            var res = JSON.stringify({'beijing':'sunny'})
            resp.end(req.query.callback+'('+res+')')
        }else{
            resp.end(JSON.stringify({'beijing':'rain'}))
        }
    }

2. CORS(Cross-Origin Resource Sharing)跨域资源共享

CORS,跨域资源共享,是一种ajax跨域请求资源的方式。(几乎所有浏览器都支持,但是ie必须10以上。)

  1. 当客户端使用XMLHttpRequest发送请求时,浏览器发现请求不符合同源策略,会加上一个请求头:origin;
<body>
    <button class="btn">获取天气</button>
</body>
<script>
    document.querySelector('.btn').addEventListener('click', function(){
        var xhr = new XMLHttpRequest()
        xhr.open('get', 'http://www.b.com:8080/getWeather', true)
        xhr.onload = function(){
            
            console.log(xhr.responseText)
        }
        xhr.send()
    })
</script>
image.png
  1. 在服务端收到请求并响应时,设置在响应结果加上Access-Control-Allow-Origin;
    '/getWeather':function(req, resp){
        resp.setHeader('Access-Control-Allow-Origin','http://www.a.com:8080')
        resp.writeHead(200, 'success')
        resp.end(JSON.stringify({'beijing':'rain'}))
    }
image.png
或者response.setHeader('Access-Control-Allow-Origin','*'),‘*’代表接收所有地址的请求。
  1. 此时浏览器判断如果该响应头包含请求头origin的值,就接收响应,否则拒绝就拿不到响应数据。
    CORS与JSONP区别:
    1. CORS与JSONP的使用目的相同,但是比JSONP更强大;
    2. JSONP只支持GET请求,CORS支持所有类型的HTTP请求;
    3. JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

3. 降域

会发现当页面嵌入iframe的时候,在不同源的二级域名情况下我们是不能通过js操作iframe里面的内容的,这时可以通过降域达到目的。

<body cz-shortcut-listen="true"><div class="ct">
  <h1>使用降域实现跨域</h1>
  <div class="main">
    <input type="text" placeholder="http://a.test.com:8080/a.html">
  </div>
  <iframe src="http://b.test.com:8080/b.html" frameborder="0"></iframe>
</div>
<script>
//URL: http://a.test.com:8080/a.html
document.querySelector('.main input').addEventListener('input', function(){
  console.log(this.value);
  window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = "test.com"
</script>
</body>

4. postMassage

在某些情况下iframe里面的服务端是愿意提供一些接口的,这时就用到了postMessage(),postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

//URL:http://www.a.com:8080/a.html
window.frames[0].postMessage(data,'*')
//URL:http://www.b.com:8080/b.html
window.addEventListener('message',function(e){
    console.log(e.data)
})

5. 服务端中转跨域

如果对方服务器不提供跨域支持怎么办呢?这是可以自己搭建server请求中转(在服务端不存在同源策略限制)。
现在我有一个天气预报页面http://www.a.com,需要向http://www.weather.com接口获取天气数据,但是这个接口不支持JSONP和CORS跨域,那么可以这样做:

  1. 搭建服务器,创建一个获取天气的接口http://www.b.com
  2. 设置接口http://www.b.com的响应头Access-Control-Allow-Origin:http://www.a.com
  3. 页面http://www.a.comhttp://www.b.com发请求
  4. http://www.b.com收到请求后,向http://www.weather.com获取天气数据,然后将天气数据返回给http://www.a.com
上一篇下一篇

猜你喜欢

热点阅读