跨域:一個域下的文檔或腳本試圖去請求另外一個域下的資源
javascript
廣義的跨域包含一下內容:html
1.資源跳轉(連接跳轉,重定向跳轉,表單提交) 2.資源請求(內部的引用,腳本script,圖片img,frame) 3.script內部發起的請求(ajax,dom請求,和js跨域調用
跨域問題出現:前端
只有瀏覽器端出現,直接用終端請求,是不會出現跨域攔截,是屬於瀏覽器端的安全策略,瀏覽器將不一樣源的請求進行了攔截,限制了跨域資源訪問
什麼是同源vue
同源策略:same origin policy,若是兩個資源(頁面)`協議`,`域名`,`端口`都相同,那麼就是同源。 即便:兩個不一樣域名指向同一個ip,也算非同源
非同源(跨域)有哪些限制java
* cookie,localstorage,indexDB沒法讀取 * Dom和JS對象沒法互通 * Ajax請求不能發送
常見的跨域demonode
URL 說明 是否容許通訊 http://www.domain.com/a.js http://www.domain.com/b.js 同一域名,不一樣文件或路徑 容許 http://www.domain.com/lab/c.js http://www.domain.com:8000/a.js http://www.domain.com/b.js 同一域名,不一樣端口 不容許 http://www.domain.com/a.js https://www.domain.com/b.js 同一域名,不一樣協議 不容許 http://www.domain.com/a.js http://192.168.4.12/b.js 域名和域名對應相同ip 不容許 http://www.domain.com/a.js http://x.domain.com/b.js 主域相同,子域不一樣 不容許 http://domain.com/c.js http://www.domain1.com/a.js http://www.domain2.com/b.js 不一樣域名 不容許
JSONPwebpack
var script = document.createElement('script') script.style = 'text/javascript' //將要請求的get地址傳到script的src屬性,而且添加回調函數 script.setAttribute('scr','http://www.domain2.com:8080/login?user=admin&callback=handleCallback') //將script標籤放入文檔 document.head.appendChild(script) //執行回調函數 function handleCallback(res){ //處理JSON格式數據 alert(JSON.stringify(res)) }
跨域資源共享ios
access-control-allow-origin
接受哪些域名跨域訪問,能夠是*
容許全部access-control-allow-origin
容許哪些源跨域xmlHttpRequest
不須要配置請求頭,簡單請求會自動帶上origin屬性var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 xhr.open('post', 'http://www.domain2.com:8080/login', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('user=admin'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } };
crossDomain
,配置爲true以後會讓請求頭攜帶orgin跨域額外信息,可是不會自動包含cookie$.ajax({ ... xhrFields: { withCredentials: true // 前端設置是否帶cookie }, crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie ... });
/* * 導入包:import javax.servlet.http.HttpServletResponse; * 接口參數中定義:HttpServletResponse response */ // 容許跨域訪問的域名:如有端口需寫全(協議+域名+端口),若沒有端口末尾不用加'/' response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); // 容許前端帶認證cookie:啓用此項後,上面的域名不能爲'*',必須指定具體的域名,不然瀏覽器會提示 response.setHeader("Access-Control-Allow-Credentials", "true"); // 提示OPTIONS預檢時,後端須要設置的兩個經常使用自定義頭 response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
反向代理(NodeJs中間件代理跨域)(Vue代理跨域)(nginx轉發代理)nginx
場景:當服務器端沒法修改cors,而且client所有換成jsonp方式比較繁瑣時,只能經過中間代理服務器,將代理服務器設置爲支持CORS或者代理服務器和請求頁面同源,使頁面能夠直接請求代理服務器,在經過代理服務器進行接口代理,代理請求目標接口地址,返回數據web
原理:跨域限制僅是瀏覽器端的安全策略,並非http協議的固有限制,因此中間服務器在參數和cookie有效的狀況下是能夠正常的請求目標服務器的,Vue(node+webpack+webpack-dev-server
)中配置proxy
就是啓動一個同源的服務進行接口代理
注意:
cors
容許跨域訪問,配置access-control-allow-header
代碼:
module.exports = { entry: {}, module: {}, ... devServer: { historyApiFallback: true, proxy: [{ context: '/login', target: 'http://www.domain2.com:8080', // 代理跨域目標接口 changeOrigin: true, secure: false, // 當代理某些https服務報錯時用 cookieDomainRewrite: 'www.domain1.com' // 能夠爲false,表示不修改 }], noInfo: true } }
var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/', proxy({ // 代理跨域目標接口 target: 'http://www.domain2.com:8080', changeOrigin: true, // 修改響應頭信息,實現跨域並容許帶cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://www.domain1.com'); res.header('Access-Control-Allow-Credentials', 'true'); }, // 修改響應信息中的cookie域名 cookieDomainRewrite: 'www.domain1.com' // 能夠爲false,表示不修改 })); app.listen(3000); console.log('Proxy server is listen at port 3000...');
#proxy服務器 server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie裏域名 index index.html index.htm; # 當用webpack-dev-server等中間件代理接口訪問nignx時,此時無瀏覽器參與,故沒有同源限制,下面的跨域配置可不啓用 add_header Access-Control-Allow-Origin http://www.domain1.com; #當前端只跨域不帶cookie時,可爲* add_header Access-Control-Allow-Credentials true; } }
其餘js HACK方法
主域相同子域不一樣場景:docment.domain+iframe
三個頁面跨域互傳 : location.hash + iframe
window.name + iframe
H5新增的postMessage(跨窗口消息互通方法)
關於iframe:
location.hash:
#
後面跟隨的時頁面片斷標識符,用來表示瀏覽器渲染哪部分頁面信息,可是改變這個值頁面不會從新刷新, 而且設置以後,全部頁面能夠經過document對象訪問該窗口的location 信息進行獲取,能夠實現巧妙跨域//父窗口能夠把信息,寫入子窗口的片斷標識符。 var src = originURL + ‘#’ + data; document.getElementById(‘myIFrame’).src = src; //子窗口經過監聽hashchange事件獲得通知。 window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // … }
同理,window.name也是一種hack方法實現跨域的方式
瀏覽器窗口有window.name屬性。這個屬性的最大特色是,不管是否同源,只要在同一個窗口裏,前一個網頁設置了這個屬性,後一個網頁能夠讀取它。
父窗口先打開一個子窗口,載入一個不一樣源的網頁,該網頁將信息寫入window.name屬性。
window.name = data;
接着,子窗口跳回一個與主窗口同域的網址。
location = ‘http://parent.url.com/xxx.html’;
而後,主窗口就能夠讀取子窗口的window.name了。
var data = document.getElementById(‘myFrame’).contentWindow.name;
這種方法的優勢是,window.name容量很大,能夠放置很是長的字符串;缺點是必須監聽子窗口window.name屬性的變化,影響網頁性能。
postMessage
經常使用的,仍是代理,還有CORS,或者是JSONP這三種方式,禁止跨域原本就是瀏覽器的一種安全策略,雖然有必定限制開發者的手腳,可是在一些特殊的網站或者安全性要求比較高的網站,網絡安全仍是不可忽視的
很是感謝:下面的文章給了我不少的幫助,感謝各位前行者的辛苦付出,能夠點擊查閱更多信息