$http 服务

参考 : https://docs.angularjs.org/api/ng/service/$http

$http 是angular 封装好的 XMLHttpRequest 请求

内部还涉及到了

$httpBackend, $httpProvider, $q  (angular的promise), $cacheFactory (angular的cache机制) 等等

angular 的思想偏向restful概念, 所以都有 GET,POST,PUT,DELTE,PATCH,HEAD 等

angular 默认的请求头 

Accept: application/json, text/plain 接受json和text

Content-Type : application/json  

如果要修改默认设置的话可以在app.config上做修改 

var app = angular.module("app", []);
app.config(function ($httpProvider) {           
    log(angular.toJson($httpProvider.defaults)); //可以看看其它默认
    $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; //我们常用的form 
    $httpProvider.defaults.headers.put["Content-Type"] = "application/x-www-form-urlencoded";
    $httpProvider.defaults.headers.patch["Content-Type"] = "application/x-www-form-urlencoded";
});

只要是default的headers,在每次发送请求的时候都会带上。

所以如果我们每个请求都有用到一些自定义的header,我们也可以写入在default.headers中 

$httpProvider.defaults.headers.common["myHeader"] = "myheaderValue";//common 表示不管任何的 method POST,GET,PUT等

这些default的header是可以在每一次我们发请求的时候通过参数来覆盖掉.

另外$http service 也提供了一个defaults的指针 (注: $httpProvider.defaults === $http.defaults )

app.controller("ctrl", function ($scope, $http) {
    $http.defaults.headers.common["myHeader"] = "abc";          
});

 

$httpProvider.defaults.transformRequest & transformResponse 

这是angular提供给我们的2个接口,在请求发送前和响应还没有触发callback前对post data 和 response data做一些处理 

它们是个数组类型,我们可以push一些函数进去 (angular默认对request和response都放入了一个方法,post的时候如果data是对象将json化,响应时如果data是json类型,将解析成对象)

在每一次的请求,我们依然可以覆盖整个数组.

var app = angular.module("app", []);
app.config(function ($httpProvider) {            
    $httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
    $httpProvider.defaults.transformRequest.shift(); //把angular default的去掉
    $httpProvider.defaults.transformRequest.push(function (postData) { //这个function不是依赖注入哦
        if (angular.isObject(postData)) { 
            return $.param(postData); //如果postData是对象就把它转成param string 返回, 这里借用了jQuery方法
        }
        return postData;
    });
    $httpProvider.defaults.transformResponse.push(function (responseData) {
        log(angular.toJson(responseData)); //响应的数据可以做一些处理
        return "data";
    });
});
app.controller("ctrl", function ($scope, $http) {
    $http({
        method: "POST",
        url: "handle.ashx",
        data: {
            key: "value"
        },
        transformResponse: [], //每一次请求也可以覆盖default
        transformResponse: $http.defaults.transformResponse.concat([function () { return "abc" }]) //如果default要保留要concat
    }).success(function (responseData) {
        log(responseData === "abc"); //true
    });
});

 

$httpProvider.defaults.cache

angular 默认cahce = false, 一样可以通过defaults去设置每个请求(当然只有GET请求可以cache)

我们也可以在每次请求覆盖设置

当同时发送2个没有缓存的请求时,angular也能处理,只发送一次(不错哦).

var app = angular.module("app", []);
app.config(function ($httpProvider) {
    $httpProvider.defaults.cache = true;          
});
app.controller("ctrl", function ($scope, $http) {
    //并发但是只会发送一个请求
    $http.get("handle.ashx");
    $http.get("handle.ashx");
     
    //我们可以为每次请求要不要使用缓存或者缓存数据
    $http({
        url: "handle.ashx",
        method: "GET",
        cahce: true
    });
    $http({
        url: "handle.ashx", 
        method: "GET",
        cache : false //强制不使用缓存,即使已存在
    });
});

  

$httpProvider.interceptors (interceptors 中文是拦截的意思)

除了之前介绍过的 transform 可以对数据做一些处理, angular也提供了另外4个时刻,分别是 onRequest, onRequestFail, onResponse, onResponseFail 

让我们做一些而外处理. 比如当我们server返回500的时候,可能我们想做一个通用的alert,或是request fail 的话自动调整一下config在尝试请求等等.

    //interceptors是数组,放入的是可以依赖注入的方法哦!
    $httpProvider.interceptors.push(["$q", function ($q) {
        return {
            request: function (config) { //config = {method, postData, url, headers} 等                            
                return config; //返回一个新的config,可以做一些统一的验证或者调整等.
            },
            requestError: function (rejection) {                      
                return $q.reject(rejection); //必须返回一个promise对象                                              
            },
            response: function (response) {                     
                return response; //这里也可以返回 promise, 甚至是把它给 $q.reject掉
            },
            responseError: function (rejection) { //rejection = { config, data, status, statusText, headers }                
                return $q.reject(rejection); //必须返回一个promise对象                  
            }
        };
    }]);

和 transform 的执行次序是这样的 interceptors.request -> transformRequest -> transformResponse -> interceptors.response

 

安全问题 ( JSON Vulnerability Protection & Cross Site Request Forgery (XSRF) Protection) 参考 : http://bijian1013.iteye.com/blog/2112233

json漏洞可以参考 : http://blog.roodo.com/rocksaying/archives/2955557.html

我个人没有理解很多,觉得只有jsonp可能引发此问题,但是jsonp一般都是非敏感数据,所以我就没认真对待了,高手可以提点我一下 ^^ 

XSRF 大家应该很熟悉了,参考 : http://blog.csdn.net/xcyuzhen/article/details/6255038

angular 对XSRF的防范是这样的,在第一次请求的时候服务器返回一个 "XSRF-TOKEN" 的cookie, 值是一个唯一的随机值,

那么之后每个$http请求都会附上一个 "X-XSRF-TOKEN" 的header, 值就是刚才那个随机数, 那么服务器可以做一个对比来确认身份。

这里给一个ASP.NET的例子

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        //当用户登入后, 访问页面
        string ANGULAR_XSRF_COOKIE_KEY = "XSRF-TOKEN";
        var token = Session["pageToken"];
        if (token == null)
        {
            string pageToken = Guid.NewGuid().ToString(); //随机数
            Session["pageToken"] = pageToken;
            Response.Cookies.Add(new HttpCookie(ANGULAR_XSRF_COOKIE_KEY)
            {
                Value = pageToken,
                Expires = DateTime.Now.AddDays(1)  //配合前台logout洗掉   
            });
        }
    }
}

$http请求基本上什么都不需要做 

public void ProcessRequest (HttpContext context) 
{
    string ANGULAR_XSRF_HEADER_KEY= "X-XSRF-TOKEN";
    string pageToken = context.Request.Headers.Get(ANGULAR_XSRF_HEADER_KEY).ToString(); //从header提取
    if(context.Session["pageToken"].ToString() == pageToken) //对比是否一直
    {
        //pass
    }   
    context.Response.ContentType = "text/plain";
    context.Response.Write(context.Request.ContentType + "123");
}

更新 : 2015-05-08

$http 返回的是一个扩展了的 promise 对象

它有多了一些属性,比如 success , error (当然原本的then 还是有的)

success 和 then 是不太一样的,then 就是典型的promise实现啦,你返回另一个promise or value 它会串连下去,

但是 success 就不会,它只能算一个void,它的返回值是被忽视的。

success(function(data){}) , then(function(response){}) ; 前者的 arguments 是response.data , 后者是整个 response 对象

$http({
    url: "//localhost:14431/api/products",
    method: "get"
}).then(function (response) { 
    success.apply(window, [response.data, response.status, response.headers, response.config]); //大概是这样调用的
    return response;
});

所以用的时候要注意哦!

更新 : 2015-09-20 

听说在angular 1.5 版本,success,error 将被废弃了,所以大家还是用 .then 就好了啦.

这里也所以下 response.headers 是一个方法 , 如果我们想获取值的话可以这样用 response.headers("Content-Type"); //value  注意:这里我用了大小写字母

如果我们想获取所有的header 可以这样写

var headerCollection = response.headers(); 

var contentType = headerCollection["Content-Type"];  //undefined 

undefined 的原因是必须用全小写字母才可以 headerCollection["content-type"]; //value

当然统一用小写就没事了 .... 哈哈

 

posted @ 2014-08-09 12:24  兴杰  阅读(2057)  评论(0编辑  收藏  举报