1. 程式人生 > >JSONP(JS進行跨域通訊)

JSONP(JS進行跨域通訊)

 

程式碼地址:https://github.com/youaresherlock/HeadFirstHtml5

在閱讀headfirsthtml5時,學習了同源策略以及JSONP。下面我簡單介紹一下:

瀏覽器的同源策略:

同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。它是由Netscape提出的一個著名的安全策略,現在所有支援JavaScript 的瀏覽器都會使用這個策略。

如果兩個頁面的協議,埠(如果有指定)和域名都相同,則兩個頁面具有相同的

下表給出了相對http://store.company.com/dir/page.html

同源檢測的示例:

URL 結果 原因
http://store.company.com/dir2/other.html 成功  
http://store.company.com/dir/inner/another.html 成功  
https://store.company.com/secure.html 失敗 不同協議 ( https和http )
http://store.company.com:81/dir/etc.html
失敗 不同埠 ( 81和80)
http://news.company.com/dir/other.html 失敗 不同域名 ( news和store )

 

跨域HTTP請求:

* 如果你需要從不同的伺服器(不同的域名)上獲取資料就需要使用跨域HTTP請求,

* 跨域請求在網頁上非常常見。很多網頁從不同伺服器上載入CSS,圖片,JS指令碼等。

* 在現代瀏覽器中,為了資料的安全,所有請求被嚴格限制在同一域名下, 如果需要

* 呼叫不同站點的資料,需要通過跨域來解決。

 

解決方案:

* 其實這個ajax請求可以被服務端拿到,但是在Javascript裡面卻拿不到服務端的repsonse

* 1.可以在請求控制器上加上header("Access-Control-Allow-Origin:*");

* 2.在IIS,Apache,Nginx可以直接配置Access-Control-Allow-Origin跨域

* 3.使用Jsonp(JSON with Padding)是json的一種"使用模式",可以讓網頁從別的

* 域名那獲取資料。通過引用js檔案傳遞資料

 

下面是從本地用瀏覽器開啟mightygumball.html,js程式碼中來請求遠端伺服器的資料,這個明顯是不同源,因此我們用基本的JSONP來解決,XMLHttpRequest物件是不可以的,除非使用上述1,2方法,從服務端入手。(另外也有我用apache搭建的簡單伺服器,可以通過瀏覽器請求url,然後載入到我的伺服器傳來的js程式碼,執行後請求遠端伺服器的資料這個案例,詳見github)

 

JSONP:

JSONP(json with padding),通過script標籤來獲取伺服器的資料,進行跨域通訊

JSONP是一種使用<script>元素獲取資料的方法,但是這種方法或者用script連結

到第三方庫都要注意安全問題,避免惡意js程式碼訪問頁面和獲取cookie

案例如下,我們用一個簡單的定時器,不斷從遠端伺服器獲取銷售資料

 

mightygumball.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script src="mightygumball.js"></script>
    <link rel="stylesheet" href="mightygumball.css">
    <title>Mighty Gumball (JSON)</title>
</head>
<body>
    <h1>Mighty Gumball Sales</h1>
    <div id="sales">

    </div>
</body>
</html>

 

mightygumball.css

/* mightgumball.css */

body {
	margin-left: 40px;
	margin-right: 40px;
}
div#sales {
	background-color: #d9d9d9;
	-webkit-border-radius: 6px;
	border-radius: 6px;
	margin: 10px 0px 0px 0px;
	padding: 0px;
	border: 1px solid #d9d9d9;
}
div.saleItem {
	font-family: Verdana, Helvetica, sans-serif;
	color: #434343;
	padding: 10px;
}
/*p:nth-child(2) 選擇所有p元素的父元素的第二個子元素*/
div.saleItem:nth-child(2n) {
	background-color: #fafafa;
}
div.saleItem:first-child {
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
	border-top-left-radius: 6px;
	border-top-right-radius: 6px;
}
/*p:last-child 選擇所有p元素的最後一個子元素*/
div.saleItem:last-child {
	-webkit-border-bottom-left-radius: 6px;
	-webkit-border-bottom-right-radius: 6px;
	border-bottom-left-radius: 6px;
	border-bottom-right-radius: 6px;
}

 

mightygumball.js

var lastReportTime = 0;
window.onload = function() {
    setInterval(handleRefresh, 3000);
}

function handleRefresh() {
    /*反覆獲取同一個url的資源,瀏覽器為了提高效率將其快取起來,因此隨機後面加個引數,伺服器端將會將其忽略
    可以看到加入後沒有快取, lasttimereporttime引數是告訴伺服器只要指定時間之後的報告*/
    var url = "http://gumball.wickedlysmart.com" 
        + "?callback=updateSales"
        + "&random=" + (new Date()).getTime()
        + "&lastreporttime=" + lastReportTime;

    var newScriptElement = document.createElement("script");
    newScriptElement.setAttribute("src", url);
    newScriptElement.setAttribute("id", "jsonp");

    var oldScriptElement = document.getElementById("jsonp");
    var head = document.getElementsByTagName("head")[0];
    if(oldScriptElement == null) {
        head.appendChild(newScriptElement);
    } else {
        head.replaceChild(newScriptElement, oldScriptElement);
    }
}

function updateSales(sales) {
    var salesDiv = document.getElementById("sales");
    for(var i = 0; i < sales.length; i++){
        var sale = sales[i];
        var div = document.createElement("div");
        div.setAttribute("class", "saleItem");
        div.innerHTML = sale.name + " sold " + sale.sales + " gumballs";
        salesDiv.appendChild(div);
    }

    if(sales.length > 0){
        lastReportTime = sales[sales.length - 1].time;
    }
}

下圖是結果: