跨域解決方案-jsonp/CORS/postMessage/hash/WebSocket/proxy

什麼是跨域

瀏覽器會有同源策略,域名,協議,端口只要有一個不一樣就是跨域.javascript

同源策略只限制瀏覽器端,跨域請求是能夠發去的,可是請求響應response被瀏覽器堵塞了,是限制了不一樣源的讀,但不限制不一樣源的寫,服務端沒有同源策略這一限制,form表單能夠跨域發送信息也是這個緣由。html

限制前端

(1) Cookie、LocalStorage 和 IndexDB 沒法讀取。vue

(2) DOM 沒法得到。html5

(3) AJAX 請求不能發送java

瀏覽器某些靜態文件加載標籤不受同源策略限制:<script>< link>< img><video><audio><iframe>git

解決跨域的方法

jsonp

  • 原理:客戶端告訴服務一個回調函數的名稱,服務器在返回的scritp裏面調用這個回調函數,同時傳進客戶端須要的數據,這樣返回的代碼就在瀏覽器執行了
  • 優缺點:
    • 經常使用方法,簡單適用,老式瀏覽器所有支持,服務器改造很是小
    • 只能實現get一種請求,不安全 容易遭到xss攻擊
// 前端頁面
<script>
  function writeDate(_date){
  document.write(_date);
}
</script>
<script src="http://192.168.0.103:9000/getDate?callback=writeDate"></script>

// 服務端返回一個腳本,在這個腳本里面執行writeDate函數:
function getDate(response, callback){
    response.writeHead(200, {"Content-Type": "text/javascript"});
    var data = "2016-2-19";
    response.end(callback + "('" + data + "')");
}

//jQuery
$.ajax({
    url: 'http://192.168.0.103:9000/getDate',
    type: 'get',
    dataType: 'jsonp',  // 請求方式爲jsonp
    jsonpCallback: "handleCallback",    // 自定義回調函數名
    data: {}
});

//Vue
this.$http.jsonp('http://192.168.0.103:9000/getDate', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})
複製代碼

CORS跨域資源共享

跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。 ----MDN(CORS)github

cors將跨域請求分爲簡單請求和非簡單請求web

簡單請求

(1) 請求方法是如下三種方法之一:HEAD/GET/POSTajax

(2)HTTP的頭信息不超出如下幾種字段:Accept/Accept-Language/Content-Language/Last-Event-ID/

​ Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

實現方法

服務端在http響應頭中添加Access-Control-Allow-origin

「*」表示任何源均可以訪問,也能夠指定能夠訪問的源

img

非簡單請求/需預檢的請求

必須首先使用 OPTIONS 方法發起一個預檢請求到服務器,返回碼是204,預檢測經過纔會真正發出請求,這才返回200。

觸發非簡單請求的條件

img

postMessage

window.postMessage(message,targetOrigin) 方法是html5新引進的特性,不受同源策略限制。

用於解決如下方面的問題: a.) 頁面和其打開的新窗口的數據傳遞 b.) 多窗口之間消息傳遞 c.) 頁面與嵌套的iframe消息傳遞 d.) 上面三個場景的跨域數據傳遞

目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支持window.postMessage方法。

// postMessage
// 窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息
Bwindow.postMessage('data', 'http://B.com');
// 在窗口B中監聽
Awindow.addEventListener('message', function (event) {
  console.log(event.origin); // 發送源,接受誰
  console.log(event.source); // Awindow的引用
  console.log(event.data);
}, false);
複製代碼

安全問題

  • 若是不但願從其餘網站接收message,不要爲message事件添加任何事件偵聽器。
  • 始終使用origin和source屬性驗證發件人的身份。
  • 始終指定精確的目標origin,而不是*。 惡意網站能夠在不知情的狀況下更改窗口的位置,所以它能夠攔截使用postMessage發送的數據。

hash

hash爲url#後的內容,hash改變頁面不刷新, 故而能夠實現跨域通訊

?後的search內容 ,也叫query 改變頁面刷新,不能作跨域通訊

// 利用hash,場景是當前頁面 A 經過iframe或frame嵌入了跨域的頁面 B
// 在A中僞代碼以下:
var B = document.getElementsByTagName('iframe');
B.src = B.src + '#' + 'data';
// 在B中的僞代碼以下
window.onhashchange = function () {
  var data = window.location.hash;
};
複製代碼

WebSocket

www.ruanyifeng.com/blog/2017/0…

HTTP 協議有一個缺陷:通訊只能由客戶端發起,作不到服務器主動向客戶端推送信息。若是服務器有連續的狀態變化,客戶端要獲知就很是麻煩。咱們只能使用"輪詢":每隔一段時候,就發出一個詢問,瞭解服務器有沒有新的信息。最典型的場景就是聊天室。

WebSocket 最大特色就是,服務器能夠主動向客戶端推送信息,客戶端也能夠主動向服務器發送信息

var ws = new WebSocket('wss://echo.websocket.org');
// 發送
ws.onopen = function (evt) {
  console.log('Connection open ...');
  ws.send('Hello WebSockets!');
};
// 接受
ws.onmessage = function (evt) {
  console.log('Received Message: ', evt.data);
  ws.close();
};
// 關閉
ws.onclose = function (evt) {
  console.log('Connection closed.');
};
複製代碼

vue-cli 3.0 本地環境proxy代理跨域

cli.vuejs.org/zh/config/#…

若是你的前端應用和後端 API 服務器沒有運行在同一個主機上,你須要在開發環境下將 API 請求代理到 API 服務器。這個問題能夠經過 vue.config.js 中的 devServer.proxy 選項來配置。

devServer.proxy 能夠是一個指向開發環境 API 服務器的字符串:

module.exports = {
  devServer: {
    proxy: 'http://localhost:4000'
  }
}
複製代碼

這會告訴開發服務器將任何未知請求 (沒有匹配到靜態文件的請求) 代理到http://localhost:4000

若是你想要更多的代理控制行爲,也可使用一個 path: options 成對的對象。完整的選項能夠查閱 http-proxy-middleware

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: '<url>',
        ws: true,
        changeOrigin: true
      },
      '/foo': {
        target: '<other_url>'
      }
    }
  }
}
複製代碼

參考:

不要再問我跨域的問題了

MDN(CORS)

MDN(postMessage)

前端常見跨域解決方案(全)

相關文章
相關標籤/搜索