本章節小編初識跨域請求和同源策略,分享獲取新知,大家一起進步
一、同源策略
什麼是同源策略
所謂同源是指,域名,協議,端口相同。
所謂“同源策略“,簡單的說就是基於安全考慮,當前域不能訪問其他域的東西。
拓展
什麼是協議,域名,端口?
解釋:假如一個網址是 http://baidu.com:8080?user=name&pwd=password
http://
是協議baidu.com
是域名(注意:前面加上“www”即www.baidu.com不是域名)8080
是端口- user=name&pwd=password 是地址帶的參數
舉例
如果你有一個服務器A,你所需要的script,css,php文件都在服務器A,你寫的html也在服務器A上,然後運行,出現了效果,如果你想在另一臺電腦上運行你的項目(注意另一臺電腦無論有沒有開啓服務器,效果還是會顯示出來的),只要把你寫在服務器A上的協議,域名,端口以及你的項目名稱複製下來,在另一臺電腦上運行,同樣會出現相同的效果,這就實現了同源。
簡單來說,就是你的協議,域名,端口甚至項目名稱都一樣,不同電腦都能實現同樣的效果。
二、跨域講解
當一個請求url的協議、域名、端口三者之間任意一個與當前頁面url不同即爲跨域
當前頁面URL | 被請求的頁面URL | 是否跨域 | 原因 |
---|---|---|---|
http:// www.test.com | http:// www.test.com/index.html | 否 | 同源(協議、域名、端口)相同 |
http:// www.test.com | https:// www.test.com/index.html | 是 | 協議不同(http/https) |
http:// www.test.com | http:// www.baidu.com | 是 | 跨域(主域名不同baidu/test) |
http:// www.test.com | http://blog.test.com | 是 | 子域名不同(www/blog) |
http:// www.test.com:8080 | http:// www.test.com:8081 | 是 | 端口號不同(8080/8081) |
舉例
如果有兩個服務器,服務器A和服務器B,服務器A上存儲了php數據,script,甚至是css這些文件,而你在服務器B上只寫了html,然後你所在的服務器B上動態創建script,css,php數據(使用ajax請求),向服務器A上請求你想要的script,css,php數請求據(使用ajax)這些文件,請求這些文件後,你再在服務器B上運行你的html,雖然你的地址是在服務器B上,但是你還是可以運行效果與在服務器A上運行的效果是一樣的,這樣就是跨域名,跨端口,跨協議,實現了跨域。
簡單來說,就是你請求的文件,只要含有“src”,“href”這些屬性,你就能在其他服務器上,請求你所需要的文件,然後在自己的服務器上運行,就實現了跨域(跨域名,跨端口,跨協議)。
三、跨域請求解決方案
關於跨域請求有很多解決方案,下面舉兩個常見的方案
①通過jsonp跨域
JSONP(JSON with Padding)是JSON的一種“使用模式”,可用於解決主流瀏覽器的跨域數據訪問的問題。
通常爲了減輕web服務器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的服務器上,在html頁面中再通過相應的標籤從不同域名下加載靜態資源,而被瀏覽器允許,基於此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域通信
小結:即是動態創建
(1)原生實現:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參一個回調函數名給後端,方便後端返回時執行這個在前端定義的回調函數
script.src = 'http://www.test.com:8080/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.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 請求方式爲jsonp
jsonpCallback: "handleCallback", // 自定義回調函數名
data: {}
});
(3)vue.js:
this.$http.jsonp('http://www.test.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
(4)後端node.js代碼示例:
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)
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
普通跨域請求:只服務端設置Access-Control-Allow-Origin即可,前端無須設置,若要帶cookie請求:前後端都需要設置。
需注意的是:由於同源策略的限制,所讀取的cookie爲跨域請求接口所在域的cookie,而非當前頁。
前端設置:
- ①原生ajax
// 前端設置是否帶cookie
xhr.withCredentials = true;
例子
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端設置是否帶cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain.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);
}
};
- ②jQuery ajax
$.ajax({
...
xhrFields: {
withCredentials: true // 前端設置是否帶cookie
},
crossDomain: true, // 會讓請求頭中包含跨域的額外信息,但不會含cookie
...
});
- ③vue框架
axios設置:
axios.defaults.withCredentials = true
vue-resource設置:
Vue.http.options.credentials = true
服務端設置
若後端設置成功,前端瀏覽器控制檯則不會出現跨域報錯信息,反之,說明沒設成功。
- Java後臺:
/*
* 導入包:import javax.servlet.http.HttpServletResponse;
* 接口參數中定義:HttpServletResponse response
*/
// 允許跨域訪問的域名:若有端口需寫全(協議+域名+端口),若沒有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain.com");
// 允許前端帶認證cookie:啓用此項後,上面的域名不能爲'*',必須指定具體的域名,否則瀏覽器會提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS預檢時,後端需要設置的兩個常用自定義頭
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
The best investment is in yourself
2020.04.26 記錄辰兮的第58篇博客