Home  >  Article  >  php教程  >  Solution to the problem that $http asynchronous background cannot obtain request parameters in AngularJS

Solution to the problem that $http asynchronous background cannot obtain request parameters in AngularJS

高洛峰
高洛峰Original
2016-12-08 09:48:331502browse

The example in this article describes the solution to the problem that the $http asynchronous background cannot obtain the request parameters in AngularJS. Share it with everyone for your reference, the details are as follows:

angular uses a different request header and data serialization method than jQuery when submitting data asynchronously, causing some background programs to be unable to parse the data normally.

Principle analysis (online analysis):

For AJAX applications (using XMLHttpRequests), the traditional way to initiate a request to the server is: obtain a reference to an XMLHttpRequest object, initiate the request, read the response, check the status code, and finally Handle server response. An example of the entire process is as follows:

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();


For simple, common and frequently repeated tasks, this is a very tedious task. If you want to reuse the above process, you should encapsulate it or use a code library.

AngularJS XHR API adheres to an interface commonly known as Promise. Since XHR is an asynchronous call method, the server's response will be returned at an uncertain point in time in the future (we hope it will be returned immediately). The Promise interface specifies how to handle this response and allows users of Promise to use it in a predictable way.

For example, we want to obtain a user's information from the server. Assume that the backend interface used to accept requests is located on the /api/user path. This interface can accept an id attribute as a URL parameter, then use Angular's core $http service An example of how to initiate an XHR request is as follows:

$http.get('api/user', {params: {id:'5'}
}).success(function(data, status, headers, config) {
  //加载成功之后做一些事
}).error(function(data, status, headers, config) {
  //处理错误
});


If you are a jQuery user, you should find that AngularJS and jQuery are very similar in handling asynchronous requests.

The $http.get method used in the above example is one of the many shortcut methods provided by AngularJS's core service $http. Similarly, if you want to use AngularJS to send a POST request to the same URL, along with some POST data, you can do it like this:

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) {
  //处理错误
});


For most common request types, there are similar Shortcut methods, these request types include: GET, HEAD, POST, DELETE, PUT, JSONP.

1. Further configure the request

Although the standard request method is relatively simple to use, it sometimes has the disadvantage of poor configurability. You will encounter difficulties if you want to implement the following things:

a. Add some authorization headers to the request.
b. Modify the way cache is handled.
c. Use some special methods to transform the sent request or transform the received response.

In these cases, you can deeply configure the request by passing an optional configuration object to the request. In the previous example, we specified an optional URL parameter using the config object. But the GET and POST methods there are some shortcuts. An example of method calling after this deep simplification is as follows:

$http(config)


The following is a basic pseudocode template for calling the previous method:

$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 and other shortcuts Methods will automatically set method parameters, so there is no need to set them manually. The config object will be passed as the last parameter to $http.get and $http.post, so this parameter can be used inside all shortcut methods. You can pass a config object to modify the request sent. The config object can set the following key values.

method: a string indicating the type of HTTP request, such as GET or POST.
url: URL string, indicating the requested absolute or relative resource path.
params: An object whose keys and values ​​are both strings (a map to be exact), representing the keys and values ​​that need to be converted into URL parameters. For example:

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


will be converted to

?key1=value&key2=value2


and will be appended to the URL. If we use a js object (rather than a string or value) as the value in the map, then the js object will be converted into a JSON string.

data: A string or object, which will be sent as request data.
timeout: The number of milliseconds to wait before the request times out.

2. Set HTTP headers

AngularJS comes with some default request headers, and all requests issued by Angular will have these default request headers. The default request headers include the following two:

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

If you want to set special request headers, you can use the following two methods. .

The first method, if you want to set the request header to every request sent out, then you can set the special request header to be used to the default value of AngularJS. These values ​​can be set via the $httpProvider.defaults.headers configuration object, usually in the configuration section of the application. So, if you want to use the "DO NOT TRACK" header for all GET requests and remove the Requested-With header for all requests, you can simply do the following:

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程序设计有所帮助。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn