ajax跨域請求-jsonp

1. 同源策略

ajax之因此須要「跨域」,罪魁禍首就是瀏覽器的同源策略。即,一個頁面的ajax只能獲取這個頁面相同源或者相同域的數據。javascript

如何叫「同源」或者「同域」呢?——協議、域名、端口號都必須相同。例如:css

http://google.com  和  https://google.com 不一樣,由於協議不一樣;html

http://localhost:8080  和  http://localhost:1000 不一樣,由於端口不一樣;前端

http://localhost:8080  和  https://google.com 不一樣,協議、域名、端口號都不一樣,根本不是一家的。java

根據同源策略,我本身作的一個網頁 http://localhost:8080/test.html 就沒法經過ajax直接獲取 http://google.com 的數據。ajax

例如,我用ajax去訪問一個不一樣域的頁面,錯誤結果是這樣的:編程

技術分享

 

你們想一想,這樣其實也有道理。若是沒有同源策略,你我均可以隨便經過ajax直接獲取其餘網站的信息,這還不亂套了。。。我本身作一個搜索界面,搜索時直接用ajax從百度獲取數據,那不成了小偷了。。。json

可是跨域訪問是少不了的,mail.163.com 的網頁可能須要從 news.163.com 域下獲取新聞信息,那怎麼辦?——開始我們的跨域之旅。(固然用iframe也能夠實現)跨域

2. 從「盜鏈」提及

互聯網的許多網站之間圖片相互盜鏈,A網站網頁的img.src直接連接到B網站的圖片地址,這是常有的事兒。說到「盜鏈」,你們第一想到的多是如何去防止盜鏈,今兒咱無論那個。瀏覽器

你再想一想「盜鏈」和「同源策略」這兩個詞之間有什麼關係?——對,矛盾!既然都「同源策略」了,怎麼還能「盜鏈」呢?

世間萬物都有矛盾,有矛盾了照樣能夠和諧共處,並不必定非要你死我活。

重點:<img>的src(獲取圖片),<link>的href(獲取css),<script>的src(獲取javascript)這三個都不符合同源策略,它們能夠跨域獲取數據。所以,你能夠直接從一些cdn上獲取jQuery,而且你網站上的圖片也隨時可能被別人盜用,全部最好加上水印!

而咱們今天的主角——jsonp——就是由於<script>的src不符合同源策略而來的。

3. JSONP

例如,域名 a.com 下有一個 a.com/test.html 網頁,域名 b.com 下有一個 b.com/data.html 網頁和 b.com/alert.js 文件。

引導第一步:簡單引用js

編寫 b.com/alert.js 以下:

alert(123);

對 a.com/test.html 編寫以下代碼:

<script type=‘text/javascript‘ src=‘http://b.com/alert.js‘/>

運行 a.com/test.html,結果很明顯,就是彈出 【123】 。

 

引導第二步:引用js返回數據

將 b.com/alert.js 修改成:

myFn(100);

將 a.com/test.html 修改成:

<script>
    function myFn ( data ) {
        alert( data + ‘px‘ );
    }
</script>
<script type=‘text/javascript‘ src=‘http://b.com/alert.js‘/>

運行 a.com/test.html,結果是彈出【 100px 】,這個應該也沒有什麼疑問。

 

引導第三步:已經跨域成功!

第二步中,若是data——即100——是我要跨域在b.com下獲取的一個數據,那麼我們這不就是已經實現跨域請求了嗎!!!

把這個過程再清晰的捋一遍:

  • <script>的src不符合同源策略;
  • 我經過給<script>的src賦值一個跨域的文件的網址(可能不是一個js文件),這個文件返回的字符串,瀏覽器會看成javascript來解析;
  • 而這段javascript中,就能夠包含着我所須要的跨域服務器端的數據;
  • 最後,我在本頁面定義一個myFn函數用來展現數據,而這段javascript中就能夠直接調用myFn函數;

 

引導第四步:引用html格式

<script>的src不必定僅僅指向javascript文件,能夠指向任何地址。例如:

將 a.com/test.html 修改成:

<script>
    function myFn ( data ) {
        alert( data + ‘px‘ );
    }
</script>
<script type=‘text/javascript‘ src=‘http://b.com/data.html‘/>

將 b.com/data.html 編寫爲:(注意,data.html中就寫如下一行代碼,多了不寫)

myFn(100); 

運行 a.com/test.html ,結果依然是【 100px 】

其中,「100」就是咱們要跨域請求的數據。

 

引導第五步:動態數據

若是要請求的數據是動態的,那就要在動態頁面中編寫。

那麼咱們就讓 a.com/test.html 去調用一個動態的aspx頁面:

<script>
    function myFn ( data ) {
        alert( data + ‘px‘ );
    }
</script>
<script type=‘text/javascript‘ src=‘http://b.com/data.aspx?callback=myFn‘/>

你們注意,咱們在 src 地址中增長了「?callback=myFn」,意思是把顯示數據的函數也動態傳過去了,而第二步、第四步都是靜態的寫在被調用的文件中的。

至於callback參數後臺如何接收,如何使用,請接着看:

在 b.com 下增長一個 b.com/data.aspx 頁面,後臺代碼以下:

 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (this.IsPostBack == false)
        {
            string callback = "";
            if (Request["callback"] != null)
            {
                callback = Request["callback"];

                //服務器端要返回的數據
                string data = "1024";

                Response.Write(callback + "(" + data + ")");
            }
        }
    }
 

代碼很簡單,獲取callback參數,而後組成一個函數的形式返回。若是「b.com/data.aspx?callback=myFn」調用的話,那麼返回的就是" myFn(1024) "。

返回的數據變成動態的了(「1024」),前端頁面用於顯示數據的函數也編程了動態的了(「callback=myFn」),可是歸根結底,形式仍是同樣的。

 

引導第六步:調用封裝

a.com/test.html 中,僅僅有一個<script>靜靜的躺在那裏,執行一次以後,就沒有做用了。

而實際狀況是,a.com/test.html 中,可能隨着用戶的操做發生若干次的調用。怎麼辦?——動態增長唄。

 
function addScriptTag(src) {
    var script = document.createElement("script");
    script.setAttribute("type", "text/javascript");
    script.src = src;
    document.body.appendChild(script);
}

function myFn (data) {
    alert(data + ‘px‘);  
}

//須要調用時:
//addScriptTag(‘b.com/data.aspx?callback=myFn‘);
 

 

4. 總結

以上層層描述的就是JSONP,你沒必要去記住它的定義,看明白了上述文字,就全能理解。

重點在於:同源策略 + <script>的src不屬於同源策略 + 經過<script>的src指向的文件返回服務器端數據。

ok,就這些!

相關文章
相關標籤/搜索