参考 : 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; });
所以用的时候要注意哦!