瀏覽器的同源策略和跨域訪問

1. 什麼是同源策略 

    理解跨域首先必需要了解同源策略。同源策略是瀏覽器上爲安全性考慮實施的很是重要的安全策略。
    何謂同源:
        URL由協議、域名、端口和路徑組成,若是兩個URL的協議、域名和端口相同,則表示他們同源。
    同源策略:
        瀏覽器的同源策略,限制了來自不一樣源的"document"或腳本,對當前"document"讀取或設置某些屬性。
        從一個域上加載的腳本不容許訪問另一個域的文檔屬性。javascript

 舉個例子:
        好比一個惡意網站的頁面經過iframe嵌入了銀行的登陸頁面(兩者不一樣源),若是沒有同源限制,惡意網頁上的javascript腳本就能夠在用戶登陸銀行的時候獲取用戶名和密碼。

    在瀏覽器中,<script>、<img>、<iframe>、<link>等標籤均可以加載跨域資源,而不受同源限制,但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
    另外同源策略只對網頁的HTML文檔作了限制,對加載的其餘靜態資源如javascript、css、圖片等仍然認爲屬於同源。css

 

 

跨域請求解決方案:html

一、 經過jsonp跨域
二、 document.domain + iframe跨域
三、 location.hash + iframe
四、 window.name + iframe跨域
五、 postMessage跨域
六、 跨域資源共享(CORS)
七、 nginx代理跨域
八、 nodejs中間件代理跨域
九、 WebSocket協議跨域前端

 

1、 經過jsonp跨域

一般爲了減輕web服務器的負載,咱們把js、css,img等靜態資源分離到另外一臺獨立域名的服務器上,在html頁面中再經過相應的標籤從不一樣域名下加載靜態資源,而被瀏覽器容許,基於此原理,咱們能夠經過動態建立script,再請求一個帶參網址實現跨域通訊。vue

1.)原生實現:java

<script> var script = document.createElement('script'); script.type = 'text/javascript'; // 傳參並指定回調執行函數爲onBack script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack'; document.head.appendChild(script); // 回調執行函數 function onBack(res) { alert(JSON.stringify(res)); } </script>

服務端返回以下(返回時即執行全局函數):node

onBack({"status": true, "user": "admin"})

2.)jquery ajax:jquery

$.ajax({
    url: 'http://www.domain2.com:8080/login', type: 'get', dataType: 'jsonp', // 請求方式爲jsonp jsonpCallback: "onBack", // 自定義回調函數名 data: {} });

3.)vue.js:nginx

this.$http.jsonp('http://www.domain2.com:8080/login', { params: {}, jsonp: 'onBack' }).then((res) => { console.log(res); })

後端node.js代碼示例:web

var querystring = require('querystring'); var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { var params = qs.parse(req.url.split('?')[1]); var fn = params.callback; // jsonp返回設置 res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.write(fn + '(' + JSON.stringify(params) + ')'); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');

jsonp缺點:只能實現get一種請求。

 

跨域資源共享(CORS)

普通跨域請求:只服務端設置Access-Control-Allow-Origin便可,前端無須設置,若要帶cookie請求:先後端都須要設置。

需注意的是:因爲同源策略的限制,所讀取的cookie爲跨域請求接口所在域的cookie,而非當前頁。若是想實現當前頁cookie的寫入,可參考下文:7、nginx反向代理中設置proxy_cookie_domain 和 8、NodeJs中間件代理中cookieDomainRewrite參數的設置。

目前,全部瀏覽器都支持該功能(IE8+:IE8/9須要使用XDomainRequest對象來支持CORS)),CORS也已經成爲主流的跨域解決方案。

一、 前端設置:

1.)原生ajax

// 前端設置是否帶cookie xhr.withCredentials = true;

示例代碼:

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 // 前端設置是否帶cookie xhr.withCredentials = true; 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); } };

2.)jQuery ajax

$.ajax({
    ...
   xhrFields: {
       withCredentials: true // 前端設置是否帶cookie    },    crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie ... });

3.)vue框架
在vue-resource封裝的ajax組件中加入如下代碼:

Vue.http.options.credentials = true
二、 服務端設置:

若後端設置成功,前端瀏覽器控制檯則不會出現跨域報錯信息,反之,說明沒設成功。

1.)Java後臺:

/* * 導入包:import javax.servlet.http.HttpServletResponse; * 接口參數中定義:HttpServletResponse response */ response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); // 如有端口需寫全(協議+域名+端口) response.setHeader("Access-Control-Allow-Credentials", "true");

2.)Nodejs後臺示例:

 
var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var postData = ''; // 數據塊接收中 req.addListener('data', function(chunk) { postData += chunk; }); // 數據接收完畢 req.addListener('end', function() { postData = qs.parse(postData); // 跨域後臺設置 res.writeHead(200, { 'Access-Control-Allow-Credentials': 'true', // 後端容許發送Cookie 'Access-Control-Allow-Origin': 'http://www.domain1.com', // 容許訪問的域(協議+域名+端口) 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:腳本沒法讀取cookie }); res.write(JSON.stringify(postData)); res.end();
});
});

server.listen('8080'); console.log('Server is running at port 8080...');
相關文章
相關標籤/搜索