ホームページ >php教程 >PHP开发 >AngularJSで$http非同期バックグラウンドがリクエストパラメータを取得できない問題の解決策

AngularJSで$http非同期バックグラウンドがリクエストパラメータを取得できない問題の解決策

高洛峰
高洛峰オリジナル
2016-12-08 09:48:331528ブラウズ

この記事の例では、$http 非同期バックグラウンドが AngularJS のリクエスト パラメーターを取得できない問題の解決策を説明します。参考のために皆さんと共有してください。詳細は次のとおりです:

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 パス上にあると仮定し、このインターフェースは URL パラメーターとして id 属性を受け入れることができます。 core $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 によって提供される多くのショートカット メソッドの 1 つです。同様に、AngularJS を使用して、同じ URL に POST リクエストをいくつかの POST データとともに送信する場合は、次のように行うことができます:

var postData = {text:'long blob of text'};
//下面这一行会被当成参数附加到URL后面,所以post请求最终会变成/api/user?id=5
var 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 が含まれます。

1. リクエストをさらに構成します

標準のリクエスト方法は比較的簡単に使用できますが、構成が難しいという欠点がある場合があります。次のことを実装する場合は、問題が発生します:

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、およびその他のショートカット メソッドは次のようになります。メソッドパラメータは自動的に設定されるため、手動で設定する必要はありません。 config オブジェクトは最後のパラメータとして $http.get および $http.post に渡されるため、このパラメータはすべてのショートカット メソッド内で使用できます。 config オブジェクトを渡して、送信されるリクエストを変更できます。config オブジェクトは次のキー値を設定できます。

メソッド: GET や POST などの HTTP リクエストのタイプを示す文字列。
url: 要求された絶対または相対リソース パスを示す URL 文字列。
params: キーと値が両方とも文字列 (正確にはマップ) であり、URL パラメーターに変換する必要があるキーと値を表すオブジェクト。例:

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


?key1=value&key2=value2


に変換され、URL に追加されます。マップ内の値として js オブジェクト (文字列や値ではなく) を使用すると、js オブジェクトは JSON 文字列に変換されます。

data: リクエストデータとして送信される文字列またはオブジェクト。
timeout: リクエストがタイムアウトになるまで待機するミリ秒数。

2. HTTP ヘッダーを設定する

AngularJS にはいくつかのデフォルトのリクエスト ヘッダーが付属しており、Angular によって発行されるすべてのリクエストにはこれらのデフォルトのリクエスト ヘッダーが含まれます。デフォルトのリクエスト ヘッダーには次の 2 つが含まれます:

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

特別なリクエスト ヘッダーを設定したい場合は、以下を使用できます。それを達成するための 2 つの方法。

最初の方法では、送信されるすべてのリクエストにリクエスト ヘッダーを設定したい場合、使用する特別なリクエスト ヘッダーを 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 + &#39;[&#39; + i + &#39;]&#39;;
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + &#39;&&#39;;
        }
      }
      else if (value instanceof Object) {
        for (subName in value) {
          subValue = value[subName];
          fullSubName = name + &#39;[&#39; + subName + &#39;]&#39;;
          innerObj = {};
          innerObj[fullSubName] = subValue;
          query += param(innerObj) + &#39;&&#39;;
        }
      }
      else if (value !== undefined && value !== null)
        query += encodeURIComponent(name) + &#39;=&#39; + encodeURIComponent(value) + &#39;&&#39;;
    }
    return query.length ? query.substr(0, query.length - 1) : query;
  };
  // Override $http service&#39;s default transformRequest
  $httpProvider.defaults.transformRequest = [function (data) {
    return angular.isObject(data) && String(data) !== &#39;[object File]&#39; ? param(data) : data;
  }];
}).config(function ($routeProvider) {
    $routeProvider
      .when(&#39;/&#39;, {
        templateUrl: &#39;views/main.html&#39;,
        controller: &#39;MainCtrl&#39;
      })
      .when(&#39;/about&#39;, {
        templateUrl: &#39;views/about.html&#39;,
        controller: &#39;AboutCtrl&#39;
      })
      .otherwise({
        redirectTo: &#39;/&#39;
      });
  });

   


希望本文所述对大家AngularJS程序设计有所帮助。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。