一、跨域是什麼
跨域是指從一個域名的網頁去請求另一個域名的資源。比如從www.baidu.com 頁面去請求 www.jd.com 的資源。跨域的嚴格一點的定義是:只要協議、域名、端口有任何一個的不同,就被當作是跨域。
二、瀏覽器爲什麼要限制跨域訪問呢(制定同源策略)?
原因就是安全問題:如果一個網頁可以隨意地訪問另外一個網站的資源,那麼就有可能在客戶完全不知情的情況下出現安全問題。比如下面的操作就有安全問題:
1、用戶訪問www.jd.com ,登陸並進行某操作,這時cookie啥的都生成並存放在瀏覽器;
2、用戶突然想起件事,不小心訪問了一個邪惡的網站 www.xe.com;
3、這時該網站就可以在它的頁面中,拿到京東cookie,比如用戶名,登陸token等,然後發起對www.jd.com 的操作。
4、如果這時瀏覽器不予限制,並且京東也沒有做響應的安全處理的話,那麼用戶的信息有可能就這麼泄露了。
三、我們爲何要研究跨域問題
因爲瀏覽器的同源策略規定某域下的客戶端在沒明確授權的情況下,不能讀寫另一個域的資源。而在實際開發中,前後端常常是相互分離的,並且前後端的項目部署也常常不在一個服務器內或者在一個服務器的不同端口下。前端想要獲取後端的數據,就必鬚髮起請求,如果不做一些處理,就會受到瀏覽器同源策略的約束。後端可以收到請求並返回數據,但是前端無法收到數據。
四、多種跨域方法
跨域可以大概分爲兩種目的:前後端分離時,前端爲了獲取後端數據而跨域;爲不同域下的前端頁面通信而跨域。
1、爲前後端分離而跨域
Cross Origin Resource Share (CORS):CORS是一個跨域資源共享方案,爲了解決跨域問題,通過增加一系列請求頭和響應頭,規範安全地進行跨站數據傳輸。
請求頭主要包括
響應頭主要包括
如何使用
客戶端只需按規範設置請求頭。服務端按規範識別並返回對應響應頭,或者安裝相應插件,修改相應框架配置文件等。具體視服務端所用的語言和框架而定。
SpringBoot 設置CORS例子
一個spring boot項目中關於CORS配置的一段代碼,更多配置可以自己研究一下。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
public CorsConfig() {
}
@Bean
public CorsFilter corsFilter() {
// 1. 添加cors配置信息
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:8080");
// 設置是否發送cookie信息
config.setAllowCredentials(true);
// 設置允許請求的方式
config.addAllowedMethod("*");
// 設置允許的header
config.addAllowedHeader("*");
// 2. 爲url添加映射路徑
UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
corsSource.registerCorsConfiguration("/**", config);
// 3. 返回重新定義好的corsSource
return new CorsFilter(corsSource);
}
}
2、JSONP 跨域
jsonp的原理就是藉助HTML中的srcipt標籤可以跨域引入資源。所以動態創建一個srcipt標籤,src爲目的接口 + get數據包 + 處理數據的函數名。後臺收到GET請求後解析並返回函數名(數據)給前端,前端script標籤動態執行處理函數。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參並指定回調執行函數爲getData
script.src = 'http://localhost:8080/users?username=xbc&callback=handleData';
document.body.appendChild(script);
// 回調執行函數
function handleData(res) {
data = JSON.stringify(res)
console.log(data);
}
</script>
</body>
</html>
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var params = querystring.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回設置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
var data = {
user: 'xbc',
password: '123456'
}
res.write(fn + '(' + JSON.stringify(data) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
3、nginx 反向代理實現跨域
目前沒有深入瞭解,後續補充。