AngularJS出現$http非同步後台無法擷取請求參數問題的解決方案_AngularJS

來源:互聯網
上載者:User

本文執行個體講述了AngularJS出現$http非同步後台無法擷取請求參數問題的解決方案。分享給大家供大家參考,具體如下:

angular在通過非同步提交資料時使用了與jQuery不一樣的要求標頭部和資料序列化方式,導致部分背景程式無法正常解析資料。

原理分析(網上的分析):

對於AJAX應用(使用XMLHttpRequests)來說,向伺服器發起請求的傳統方式是:擷取一個XMLHttpRequest對象的引用、發起請求、讀取響應、檢查狀態代碼,最後處理服務端的響應。整個過程樣本如下:

var xmlhttp = new XMLHttpRequest();xmlhttp.onreadystatechange = function() {  if(xmlhttp.readystate == 4 && xmlhttp.status == 200) {    var response = xmlhttp.responseText;  }else if(xmlhttp.status == 400) { //或者可以是任何以4開頭的狀態代碼    //優雅地處理錯誤  }};//建立串連xmlhttp.open("GET", "http://myserver/api", true);//發起請求xmlhttp.send();

對於簡單、常用而且會經常重複的任務來說,這是一種很煩瑣的工作。如果你想複用以上過程,你應該進行封裝或者使用程式碼程式庫。

AngularJS XHR API遵守一種通常被稱為Promise的介面。由於XHR是非同步呼叫的方法,所以服務端的響應會在未來某個不確定的時間點上返回(我們希望它立即能返回)。Promise介面規定了處理這種響應的方式,並且允許Promise的使用者以一種可預見的方式來使用它。

例如,我們要從服務端擷取一個使用者的資訊,假設用來接受請求的後台介面位於/api/user路徑上,此介面可以接受一個id屬性作為URL參數,那麼使用Angular的核心$http服務發起XHR請求的方法樣本如下:

$http.get('api/user', {params: {id:'5'}}).success(function(data, status, headers, config) {  //載入成功之後做一些事}).error(function(data, status, headers, config) {  //處理錯誤});

如果你是jQuery使用者,你應該會發現,AngularJS和jQuery在對非同步請求的處理方面非常類似。

上面例子中使用的$http.get方法是AngularJS的核心服務$http所提供的眾多快捷方法之一。類似地,如果你想使用AngularJS向同一個URL發送POST請求,同時帶上一些POST資料,你可以像下面這樣做:

var postData = {text:'long blob of text'};//下面這一行會被當成參數附加到URL後面,所以post請求最終會變成/api/user?id=5var config = {params: {id: '5'}};$http.post('api/user', postData, config).success(function(data, status, headers, config) {  //成功之後做一些事情}).error(function(data, status, headers, config) {  //處理錯誤});

對於大多數常用的請求類型,都有類似的快捷方法,這些請求類型包括:GET、HEAD、POST、DELETE、PUT、JSONP。

一.進一步配置請求

雖然標準的請求方式使用起來比較簡單,但是,有時候會存在可配置性不佳的缺點。如果你想要實現下面這些事情就會遇到困難:

a.給請求加上一些授權頭。
b.修改對緩衝的處理方式。
c.用一些特殊的方式來變換髮送出去的請求,或者變換接收到的響應。

在這些情況下,你可以給請求傳遞一個可選的設定物件,從而對請求進行深度配置。在前面的例子中,我們使用config對象指定了一個可選的URL參數。但是那裡的GET和POST方法是一些捷徑。這種深度簡化之後的方法調用樣本如下:

$http(config)

下面是一個基本的虛擬碼模板,用來調用前面的這個方法:

$http({  method: string,  url: string,  params: object,  data: string or object,  headers: object,  transformRequest: function transform(data, headersGetter) or an array of functions,  transformResponse: function transform(data, headersGetter) or an array of functions,  cache: boolean or Cache object,  timeout: number,  withCredentials: boolean});

GET、POST及其他快捷方法都會自動化佈建method參數,所以不需要手動設定。config對象會作為最後一個參數傳遞給$http.get和$http.post,所以,在所有的快捷方法內部都可以使用這個參數。你可以傳遞config對象來修改發送的請求,config對象可以設定以下索引值。

method:一個字串,表示HTTP請求的類型,例如GET或者POST。
url:URL字串,表示請求的絕對或者相對資源路徑。
params:一個鍵和值都是字串的對象(確切來說是一個map),表示需要轉換成URL參數的鍵和值。例如:

[{key1: 'value1', key2: 'value2'}]

將會被轉換成

?key1=value&key2=value2

並會被附加到URL後面。如果我們使用js對象(而不是字串或者數值)作為map中的值,那麼這個js對象會被轉換成JSON字串。

data:一個字串或者對象,它會被當作請求資料發送。
timeout:在請求逾時之前需要等待的毫秒數。

二.設定HTTP頭

AngularJS帶有一些預設的要求標頭,Angular發出的所有請求上都會帶有這些預設的要求標頭資訊。預設要求標頭包括以下兩個:

1.Accept:appliction/json,text/pain,/
2.X-Requested-With: XMLHttpRequest

如果想設定特殊的要求標頭,可以用如下兩種方法實現。

第一種方法,如果你想把要求標頭設定到每一個發送出去的請求上,那麼你可以把需要使用的特殊要求標頭設定成AngularJS的預設值。這些值可以通過$httpProvider.defaults.headers設定物件來設定,通常會在應用的配置部分來做這件事情。所以,如果你想對所有的GET請求使用“DO NOT TRACK"頭,同時對所有請求刪除Requested-With頭,可以簡單地操作如下:

angular.module('MyApp', []).  config(function($httpProvider) {    //刪除AngularJS預設的X-Request-With頭    delete $httpProvider.default.headers.common['X-Requested-With'];    //為所有GET請求設定DO NOT TRACK    $httpProvider.default.headers.get['DNT'] = '1';});

如果你只想對某些特定的請求佈建要求頭,但不把它們作為預設值,那麼你可以把頭資訊作為設定物件的一部分傳遞給$http服務。同樣的,自訂頭資訊也可以作為第二個參數的一部分傳遞給GET請求,第二個參數還可以同時接受URL參數。

$http.get('api/user', {   //設定Authorization(授權)頭。在真實的應用中,你需要到一個服務裡面去擷取auth令牌   headers: {'Authorization': 'Basic Qzsda231231'},   params: {id:5}}).success(function() {//處理成功的情況 });

三.緩衝響應

對於HTTP GET請求,AngularJS提供了一個開箱即用的簡單緩衝機制。預設情況下它對所有請求類型都不可用,為了啟用緩衝,你需要做一些配置:

$http.get('http://server/myapi', {  cache: true}).success(function() {//處理成功的情況});

這樣就可以啟用緩衝,然後AngularJS將會緩衝來自伺服器的響應。下一次向同一個URL發送請求的時候,AngularJS將會返回緩衝中的響應內容。緩衝也是智能的,所以即使你向同一個URL發送多次類比的請求,緩衝也只會向伺服器發送一個請求,而且在收到服務端的響應之後,響應的內容會被分發給所有請求。

但是,這樣做有些不太實用,因為使用者會先看到緩衝的舊結果,然後看到新的結果突然出現。例如,當使用者即將點擊一條資料時,它可能會突然發生變化。

注意,從本質上來說,響應(即使是從緩衝中讀取的)依然是非同步。換句話說,在第一次發出請求的時候,你應該使用處理非同步請求的方式來編碼。

四.轉換請求和響應

對於所有通過$http服務發出的請求和收到的響應來說,AngularJS都會進行一些基本的轉換,包括如下內容。

1.轉換請求

如果請求的設定物件屬性中包含JS對象,那麼就把這個對象序列化成JSON格式。

2.轉換響應

如果檢測到了XSRF(Cross Site Request Forgery的縮寫,意為跨站請求偽造,這是跨站指令碼攻擊的一種方式)首碼,則直接丟棄。如果檢測到了JSON響應,則使用JSON解析器對它進行還原序列化。

如果你不需要其中的某些轉換,或者想自已進行轉換,可以在配置項裡面傳入自已的函數。這些函數會擷取HTTP的request/response體以及協議頭資訊,然後輸出序列化、修改之後的版本。可以使用transformLRequest和transformResponse作為key來配置這些轉換函式,而這兩個函數在模組的config函數中是用$httpProvider服務來配置的。

我們什麼時候需要使用這些東西呢?假設我們有一個服務,它更適合用jQuery的方式來操作。POST資料使用key1=val1&key2=val2(也就是字串)形式來代替{key1:val1, key2:val2}JSON格式。我們可以在每個請求中來進行這種轉換,也可以添加一個獨立transformRequest調用,對於當前這個例子來說,我們打算添加一個通用的transformRequest,這樣所有發出的請求都會進行這種從JSON到字串的轉換。下面就是實現方式:

var module = angular.module('myApp');module.config(function($httpProvider) {  $httpProvider.defaults.transformRequest = function(data) {     //使用jQuery的param方法把JSON資料轉換成字串形式     return $.param(data);   };});

實列配置:

在使用中發現背景程式還是無法解析angular提交的資料,對比後發現頭部缺少‘X-Requested-With'項

所以在配置中加入:

複製代碼 代碼如下:
$httpProvider.defaults.headers.post['X-Requested-With'] = 'XMLHttpRequest'

下面貼入測試時的部分配置代碼:

angular.module('app', [  'ngAnimate',  'ngCookies',  'ngResource',  'ngRoute',  'ngSanitize',  'ngTouch'],function ($httpProvider) {  // 頭部配置  $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';  $httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript, */*; q=0.01';  $httpProvider.defaults.headers.post['X-Requested-With'] = 'XMLHttpRequest';  /**   * 重寫angular的param方法,使angular使用jquery一樣的資料序列化方式 The workhorse; converts an object to x-www-form-urlencoded serialization.   * @param {Object} obj   * @return {String}   */  var param = function (obj) {    var query = '', name, value, fullSubName, subName, subValue, innerObj, i;    for (name in obj) {      value = obj[name];      if (value instanceof Array) {        for (i = 0; i < value.length; ++i) {          subValue = value[i];          fullSubName = name + '[' + i + ']';          innerObj = {};          innerObj[fullSubName] = subValue;          query += param(innerObj) + '&';        }      }      else if (value instanceof Object) {        for (subName in value) {          subValue = value[subName];          fullSubName = name + '[' + subName + ']';          innerObj = {};          innerObj[fullSubName] = subValue;          query += param(innerObj) + '&';        }      }      else if (value !== undefined && value !== null)        query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';    }    return query.length ? query.substr(0, query.length - 1) : query;  };  // Override $http service's default transformRequest  $httpProvider.defaults.transformRequest = [function (data) {    return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;  }];}).config(function ($routeProvider) {    $routeProvider      .when('/', {        templateUrl: 'views/main.html',        controller: 'MainCtrl'      })      .when('/about', {        templateUrl: 'views/about.html',        controller: 'AboutCtrl'      })      .otherwise({        redirectTo: '/'      });  });

希望本文所述對大家AngularJS程式設計有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.