今天早上幫助同學看了一個AngularJS的問題,主要是請求中出現了跨域訪問,請求被阻止。
下面是她給我的代碼:
<html ng-app="myApp"> <head> <meta charset="UTF-8"> <title>Title</title> <!--<script src="../js/jquery-1.11.0.js"></script>--> <script src="angular.min.js"></script> <script> angular.module("myApp",[]).controller("test",["$scope","$http",function($scope,$http){ $http.get("http://datainfo.duapp.com/shopdata/getGoods.php?classID=1") .success(function(response){ $scope.myarr = response.sites; }) }]) </script> </head> <body> <div ng-controller="test"> <ul> <li ng-repeat="data in myarr"> <img src="{{data.goodsListImg}}"/ alt="解析AngularJS中get請求URL出現的跨域問題" > <p>名称:<span>{{data.goodsName}}</span></p> <p>价格:<span>{{data.price|currency:"¥"}}</span></p> </li> </ul> </div> </body> </html>
出現的問題
我們可以看到他是通過$http的get方式訪問URL,一直訪問不了,我將具體的response打印到控制台上面,也使出現了問題。
這個是瀏覽器的跨域造成的,之前的學習中我也不是很清楚這個,只是知道由於不是在同一個域名下面訪問的此域名下的資源就會造成跨域。其實之前看到這個是以為請求的格式有問題,回傳的json資料到不了。
下面是json格式回傳的資料。
按照她給我的URL,我發現在json資料前面有一個callback,這個是php中的回調函數,結果網上一搜發現get請求對於這種回調函數是沒有作用的。
解決辦法
必須使用下面的這種辦法來處理這種有callback的jsonp格式的資料。
<script> var myApp = angular.module("App", []); myApp.controller("test", function($scope, $http) { // 回调函数用法 myUrl = "http://datainfo.duapp.com/shopdata/getGoods.php?callback=JSON_CALLBACK"; $http.jsonp(myUrl).success(function(response) { console.log(response); }); }); </script>
注意兩點:
使用$http.jsonp()請求資料;(解決了跨域的問題)
在URL後面加上callback=JSON_CALLBACK字元;
這樣就可以正常的存取資料。其實對於json個格式的資料我們要是想知道那裡有錯誤,有一種辦法是將其列印到瀏覽器的控制台中,這樣我們就可以看到具體的流程和結果。
完整程式碼
<!DOCTYPE html> <html ng-app="App"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="angular.min.js"></script> <script> var myApp = angular.module("App", []); myApp.controller("test", function($scope, $http) { // 回调函数用法 myUrl = "http://datainfo.duapp.com/shopdata/getGoods.php?callback=JSON_CALLBACK"; $http.jsonp(myUrl).success(function(response) { console.log(response); $scope.myarr = response; }); }); </script> </head> <body> <div ng-controller="test"> <ul> <li ng-repeat="data in myarr"> <!--scr里面的angularJS不可以这样写--> <img src="{{data.goodsListImg}}" / alt="解析AngularJS中get請求URL出現的跨域問題" > <p>名称:<span>{{data.goodsName}}</span></p> <p>价格:<span>{{data.price|currency:"¥"}}</span></p> </li> </ul> </div> </body>
自動將我們的JSON_CALLBACK替換成了下面的字符,這應該是AngularJS替換的。
引用
跨域是如何解決的:
透過json來傳遞數據,靠jsonp來跨域,json是一種數據交換格式,而jsonp是一種靠開發人員的聰明才智的一種非官方跨域資料互動協定;
JSONP是如何產生的:
一個眾所周知的問題,Ajax直接請求普通文件存在跨域無權限訪問的問題,甭管你是靜態頁面、動態網頁、web服務、WCF,只要是跨域請求,一律不准;
不過我們又發現,Web頁面上調用js檔案時則不受是否跨域的影響(不僅如此,我們還發現凡是擁有」src」這個屬性的標籤都擁有跨域的能力,例如<script>、<img alt="解析AngularJS中get請求URL出現的跨域問題" >、<iframe>);</script>
於是可以判斷,當前階段如果想透過純web端(ActiveX控制項、服務端代理、屬於未來的HTML5之Websocket等方式不算)跨域存取資料就只有一種可能,那就是在遠端伺服器上設法把資料裝進js格式的檔案裡,供客戶端呼叫和進一步處理;
恰巧我們已經知道有一種叫做JSON的純字元資料格式可以簡潔的描述複雜數據,更妙的是JSON還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數據;
這樣子解決方案就呼之欲出了,web客戶端透過與呼叫腳本一模一樣的方式,來呼叫跨域伺服器上動態產生的js格式文件(一般以JSON為後綴),顯而易見,伺服器之所以要動態產生JSON文件,目的就在於把客戶端需要的數據裝入進去。
客戶端在對JSON檔案呼叫成功之後,也就獲得了自己所需的數據,剩下的就是按照自己需求進行處理和展現了,這種獲取遠端資料的方式看起來非常像AJAX,但其實並不一樣。
為了方便客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作JSONP,該協議的一個要點就是允許用戶傳遞一個callback參數給服務端,然後服務端返回數據時會將這個callback參數作為函數名稱來包裹住JSON數據,這樣客戶端就可以隨意自訂自己的函數來自動處理回傳資料了。
AngularJS中處理jsonp資料
使用$http.jsonp()函數來傳送請求;
指定callback和回呼函數名,當函數名稱為JSON_CALLBACK時,會回呼succccess,JSON_CALCALACKACKACK必須全部大寫;指定其它回調函數,但必須定義在window下的全局函數;
URL中必須添加callback;
瀏覽器是存在同源策略的,在全局層面禁止了頁面加載或執行與自身來源不同的域的任何腳本;JSONP是一種可以繞過瀏覽器的安全限制,從不同的域請求資料的方法;
這個解釋足以理解跨域問題和為什麼需要使用JSONP?