多種跨域方案

同源策略

說到跨域就離不開瀏覽器的同源策略

  • 協議
  • 域名
  • 端口號

只要有一個不一樣,就是跨域html

非同源下

非同源下,三種行爲會受到限制jquery

  • Cookie、LocalStorage 和 IndexDB 沒法讀取。
  • DOM 沒法得到
  • AJAX 請求不能發送

跨域最經常使用的方案

  • jsonp(只能發送get請求)
  • cors
  • postMessage
  • document.domain
  • window.name
  • location.hash
  • http-proxy
  • nginx
  • websocket

本身實現一個jsonp

jsonp實際上返回的是一個函數調用

function jsonp(url,data,callback){
    var scriptObj = document.createElement('script');
    var head = document.getElementsByTagName('head')[0];
    var fnName = 'jquery_'+new Date().getTime();
    var arr = []
    for(var key in data){
        console.log(key)
        arr.push(key+'='+data[key]);
    }
    data = arr.join('&');
    window[fnName] = function(json){
        callback(json);
    }
    scriptObj.src = url + '?' + data + '&'+callback+'='+fnName;
    head.appendChild(scriptObj);
}
jsonp('http://10.252.55.52:1337/user/socialInfo',{
    page:1,
    pageList:5,
    type:1
},function(data){
    console.log(data)
})

function jsonp({url,params,cb}){
    return new Promise((resolve,reject)=>{
        window[cb] = function(data){
            resolve(data)
        }
        params = {...params,cb}
        let arrs = [];
        for(let key in params){
            arrs.push(`${key}=${params[key]}`)
        }
        let script = document.createElement('script')
        script.src = `${url}?${arrs.join('&')}`
        document.body.appendChild(script)
    })
}
jsonp({
    url:'',
    params:{},
    cb:'show'
}).then(data=>{
    console.log(data)
})
複製代碼

cors

cors方式解決跨域問題,每每是須要在服務端設置一些請求頭

咱們能夠經過 req.headers.origin 獲取origin 下面是經常使用的一些請求頭的設置nginx

setHeader('Access-Control-Allow-Origin':origin) //容許哪一個源能夠訪問我web

setHeader('Access-Control-Allow-Headers':) //容許攜帶哪一個頭訪問我json

setHeader('Access-Control-Expose-Headers':) //容許返回的頭api

setHeader('Access-Control-Allow-Methods':) //響應標頭指定響應訪問所述資源到時容許的一種或多種方法跨域

setHeader('Access-Control-Max-Age':) //用來指定本次預檢請求的有效期,單位爲秒瀏覽器

setHeader('Access-Control-Allow-Credentials':true)websocket

postMessage

postMessage()方法容許來自不一樣源的腳本採用異步方式進行有限的通訊,能夠實現跨文本檔、多窗口、跨域消息傳遞。app

舉例

假若有一個頁面a.html 位於 www.test.com

在a.html 經過iframe嵌入b.html,b.html位於www.domain.com下

<iframe src="http://www.domain.com/b.html" frameborder="0" id="frame"></iframe>
複製代碼

若是a.hhtml想和iframe通信的話,能夠以下操做

let frame = doucument.getElementById('frame') //想和誰通信,就先獲取這個窗口,此時咱們須要的iframe裏的window

frame.contentWindow.postMessage('你好啊',http://www.domain.com) //發送消息,後面要寫明是給哪一個域發的
複製代碼

在b.html接收

window.onmessage = function(e){
    console.log(e.data)
    e.source.send('我很差',e.origin) //再回復消息
}
或者
document.addEventListener('message',  function(e){
   // content..... 
   }
)
複製代碼

document.domain

利用document.domain 實現跨域:

前提條件:這兩個域名必須屬於同一個一級域名,並且所用的協議,端口都要一致,不然沒法利用document.domain進行跨域.

例如

www.sojson.com 下指到sojson.com 是能夠的。

icp.sojson.com 下指到 sojson.com 是能夠的。

可是

www.sojson.com 下指到 www.baidu.com 是不行的。

sojson.com 指到 baidu.com 仍是不行的

若是咱們要在當前頁面下,「www.sojson.com/shiro」

上傳圖片到

"cdn.sojson.com/images/" 上去

須要在兩個頁面都寫上

if(document.domain !='sojson.com'){
    document.domain = 'sojson.com';
}
複製代碼

window.name

對於這個方案個人理解是

有一個a.html 位於www.test.com下

有一個b.html 位於www.domain.com下

兩個頁面想通信的話

咱們須要在a.html頁面引入一個iframe

<iframe src="http://www.domain.com/b.html" frameborder="0" id="frame" onload="load"></iframe>
let first = true //是否第一次加載
function load(){
    if(first){
        let iframe = document.getElementById('frame')
        iframe.src='http://www.test.com/b.html' //最後必須把b.html設置爲和a.html同域名的,這樣才能獲取iframe.contentWindow.name,否則會受同源策略的影響
        first = false
    }else{
        console.log(iframe.contentWindow.name)
    }
}
複製代碼

iframe.contentWindow.name就能夠獲取到這個數據了

在b.html咱們能夠把想傳遞的數據放到 window.name上

window.name='你好啊'
複製代碼

location.hash

有一個a.html 位於www.test.com下

有一個c.html 位於www.domain.com下

如今a.html想訪問c.html

a.html

<iframe src="http://www.domain.com/c.html#iloveyou"></iframe>

wondiw.onhashchange = function(e){
    
}
或者
document.addEventListener('hashchange',  function(e){
   // content..... 
   }
)
複製代碼

c.html

console.log(window.location.hash) //獲取這個hash值
let iframe = document.createElement('iframe')
iframe.src='http://www.test.com/b.html#idontloveyou"'
document.body.appendChild(iframe)
複製代碼

b.html

window.parent.parent.location.hash = location.hash
複製代碼

websocket

websocket屬於高級api,日常咱們通常都使用socket.io去進行兼容

服務端須要先安裝ws

服務端代碼以下:

let WebSocket = require('ws')
let wss = new WebSocket.Server({port:3000})
wss.on('connection',function(ws){
    ws.on('message',function(data){ //服務端接收消息
        console.log(data)
        ws.send('我很差') //服務端發送消息
    })
})
複製代碼

客戶端代碼以下:

let socket = new WebSocket('ws://localhost:3000')
socket.onopen = function(){
    socket.send('你好啊')
}
socket.onmessage = function(e){
    console.log(e.data) // 客戶端接收消息
}
複製代碼

nginx

首先安裝nginx

若是是mac的話

brew install nginx //安裝nginx

nginx.conf //配置文件

下面是一些經常使用的配置

add_header "Access-Control-Allow-origin" "*"

相關文章
相關標籤/搜索