同源策略&JSONP跨域
同源策略
對于同源的定義,MDN給出了這樣的解釋:如果兩個頁面的協議,端口(如果有指定)和主機都相同,則兩個頁面具有相同的源。
如何確定兩個頁面是否同源,只要比較兩個頁面的協議、域名和端口即可。
假設有這樣一個頁面http://zhihu.com/main.html,相對于它給出同源檢測的示例:

同源策略是瀏覽器最核心也最基本的安全功能。保證用戶信息的安全,防止惡意的網站竊取數據。限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的重要安全機制。
協議、端口、域名只要有一個不相同,就不符合同源策略,就會出現跨域。最常見的就是AJAX請求數據。
跨域的解決辦法
JSONP
JSONP是如何產生的呢?
1.我們都知道使用AJAX直接請求普通文件存在跨域無權限訪問的問題,甭管你是什么,只要你是跨域請求,一律不準不可以的;
2.但是我們知道HTML中的<script><img><iframe>
等標簽不受同源策略的影響,擁有跨域的能力。那我們是否能利用這個特性從其他域下獲取數據呢
3.我們得出結論,要想在web端就跨域訪問其他域的數據就有一個辦法,那就是把數據裝進 JS 格式的文件里,這樣客戶端就能夠調用了。
4.但是獲取的數據是做為 JS 來執行。于是就有一個問題,數據是 JSON 格式的數據,直接作為 JS 運行的話我如何去得到這個數據來操作呢?
5.于是我們想到是否可以提前在頁面上聲明一個函數,通過接口傳參的方式發送給后臺,在經過后臺處理發送給前端(所以JSONP 需要對應接口的后端的配合才能實現。)
示例:
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
這個請求到達后端后,后端會去解析callback這個參數獲取到字符串showData,在發送數據做如下處理:
之前后端返回數據: {"city": "hangzhou", "weather": "晴天"} 現在后端返回數據: showData({"city": "hangzhou", "weather": "晴天"}) 前端script標簽在加載數據后會把 「showData({“city”: “hangzhou”, “weather”: “晴天”})」做為 js 來執行,這實際上就是調用showData這個函數,同時參數是 {“city”: “hangzhou”, “weather”: “晴天”}。 用戶只需要在加載提前在頁面定義好showData這個全局函數,在函數內部處理參數即可。
<script>
function showData(ret){
console.log(ret);
}
</script>
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
JSONP是通過 script 標簽加載數據的方式去獲取數據當做 JS 代碼來執行 提前在頁面上聲明一個函數,函數名通過接口傳參的方式傳給后臺,后臺解析到函數名后在原始數據上「包裹」這個函數名,發送給前端。換句話說,JSONP 需要對應接口的后端的配合才能實現。
具體實現 :
server.js代碼

index.html代碼

打開Git Bash,進入server.js所在文件夾,輸入 node server.js ,瀏覽器打開 http://localhost:8080/index.html
于是我們得出JSONP的原理:
- JSONP本質上是利用
<script><img><iframe>
等標簽不受同源策略限制,可以從不同域加載并執行資源的特性,來實現數據跨域傳輸。 - JSONP由兩部分組成:回調函數和數據。回調函數是當響應到來時應該在頁面中調用的函數,而數據就是傳入回調函數中的JSON數據。
- JSONP的想法就是,與服務端約定好一個回調函數名,服務端接收到請求后,將返回一段 JS代碼,在這段JS代碼中調用了約定好的回調函數,并且將數據作為參數進行傳遞。當網頁接收到這段 Javascript 代碼后,就會執行這個回調函數,這時數據已經成功傳輸到客戶端了。