1. 什麼是跨域
跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源
一般指
1.) 資源跳轉: A鏈接、重定向、表單提交
2.) 資源嵌入: link、script、img、frame等dom標籤,還有樣式中background:url()、@font-face()等文件外鏈
3.) 腳本請求: js發起的ajax請求、dom和js對象的跨域操作等
我們通常所說的跨域是指的瀏覽器同源策略限制的一類請求場景。
同源策略
同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。
同源策略一般限制
1.) Cookie、LocalStorage 和 IndexDB 無法讀取
2.) DOM 和 Js對象無法獲得
3.) AJAX 請求不能發送
常見的跨域場景
url | 說明 | 是否允許通信 |
---|---|---|
http://www.baidu.com/1.js http://www.baidu.com/2.js | 同一域名,不同文件或路徑 | 允許 |
http://www.baidu.com:8000/1.js http://www.baidu.com/2.js | 同一域名,不同端口 | 不允許 |
http://www.baidu.com/1.js https://www.baidu.com/2.js | 同一域名,不同協議 | 不允許 |
http://www.baidu.com/1.js http://192.168.14.52/12.js | 域名和域名對應相同ip | 不允許 |
http://www.baidu.com/1.js http://x.baidu.com/1112.js | 主域相同,子域不同 | 不允許 |
http://www.baidu1.com/a.js http://www.baidu2.com/b.js | 不同域名 | 不允許 |
跨域解決方案
1、 通過jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 跨域資源共享(CORS)
6、 nginx代理跨域
7、 nodejs中間件代理跨域
8、 WebSocket協議跨域
一,通過jsonp跨域
爲了減輕web服務器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的服務器上,在html頁面中再通過相應的標籤從不同域名下加載靜態資源,而被瀏覽器允許,基於此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域通信。
1.原生實現
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參一個回調函數名給後端,方便後端返回時執行這個在前端定義的回調函數
script.src = 'http://www.baidu.com:8081/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回調執行函數
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
服務端返回如下(返回時即執行全局函數):
handleCallback({"status": true, "user": "admin"})
2.jquery ajax
$.ajax({
url: 'http://www.baidu.com:8081/login',
type: 'get',
dataType: 'jsonp', // 請求方式爲jsonp
jsonpCallback: "handleCallback", // 自定義回調函數名
data: {}
});
3.vue
this.$http.jsonp('http://www.baidu.com:8081/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
後端node.js代碼
const querystring = require('querystring');
const http = require('http');
const server = http.createServer();
server.on('request', function(req, res) {
const params = qs.parse(req.url.split('?')[1]);
const fn = params.callback;
// jsonp返回設置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8081');
console.log('Server is running at port 8081...');
jsonp缺點:只能實現get一種請求。
二、 document.domain + iframe跨域
只限於主域相同,子域不同的跨域應用場景。
實現原理:兩個頁面都通過js強制設置document.domain爲基礎主域,就實現了同域。
1.父窗口:(http://www.baidu.com/1.html)
<iframe id="iframe" src="http://child.baidu.com/2.html"></iframe>
<script>
document.baidu = 'baidu.com';
var user = 'admin';
</script>
2.子窗口:(http://www.baidu.com/2.html)
<script>
document.baidu = 'baidu.com';
// 獲取父窗口中變量
alert('get js data from parent ---> ' + window.parent.user);
</script>
剩下跨域解決方式在 簡單瞭解跨域及其解決方案(二) 裏進行說明