Angular學(xué)習(xí)筆記(11)—XHR實(shí)踐

跨域和同源策略

瀏覽器在全局層面禁止了頁面加載或執(zhí)行與自身來源不同的域的任何腳本。
同源策略允許頁面從同一個站點(diǎn)加載和執(zhí)行特定的腳本。瀏覽器通過對比每一個資源的協(xié)議、主機(jī)名和端口號來判斷資源是否與頁面同源。站外其他來源的腳本同頁面的交互則被嚴(yán)格限制。 跨域資源共享(Cross Origin Resource Sharing,CORS)是一個解決跨域問題的好方法,從而可以使用XHR從不同的源加載數(shù)據(jù)和資源。
除CORS以外還有幾個方法可以用來從外部的數(shù)據(jù)源將數(shù)據(jù)加載到應(yīng)用中:

  • JSONP
  • CORS
  • 服務(wù)器代理

JSONP

JSONP是一種可以繞過瀏覽器的安全限制,從不同的域請求數(shù)據(jù)的方法。使用JSONP需要服務(wù)器端提供必要的支持。
JSONP的原理是通過<script>標(biāo)簽發(fā)起一個GET請求來取代XHR請求。JSONP生成一個<script>標(biāo)簽并插到DOM中,然后瀏覽器會接管并向src屬性所指向的地址發(fā)送請求。當(dāng)服務(wù)器返回請求時,響應(yīng)結(jié)果會被包裝成一個JS函數(shù),并由該請求所對應(yīng)的回調(diào)函數(shù)調(diào)用。
AngularJS在$http服務(wù)中提供了一個JSONP輔助函數(shù)。通過$http服務(wù)的jsonp方法可以發(fā)送請求。

$http.jsonp("https://api.github.com?callback=JSON_CALLBACK").success(function(data) { 
    // 數(shù)據(jù)
});

當(dāng)請求被發(fā)送時,AngularJS會在DOM中生成一個如下所示的<script>標(biāo)簽。

<script src="https://api.github.com?callback=angular.callbacks._0" 
    type="text/javascript"></script>

JSON_CALLBACK被替換成了一個特地為此請求生成的自定義函數(shù)。
當(dāng)支持JSONP的服務(wù)器返回?cái)?shù)據(jù)時,數(shù)據(jù)會被包裝在由AngularJS生成的具名函數(shù)angular.callbacks._0中。
在這個例子中,服務(wù)器會返回包含在回調(diào)函數(shù)中的JSON數(shù)據(jù),響應(yīng)看起來如下所示:

// 簡寫
angular.callbacks._0({
    'meta': {
        'X-RateLimit-Limit': '60',
        'status': 200
    },
    'data': {
        'current_user_url': 'https://api.github.com/user' 
    }
})

當(dāng)AngularJS調(diào)用指定的回調(diào)函數(shù)時會對$httppromise對象進(jìn)行resolve。
當(dāng)我們自己開發(fā)支持JSONP的后端服務(wù)時,要確保響應(yīng)的數(shù)據(jù)被包含在請求所指定的回調(diào)函數(shù)中。
使用JSONP需要意識到潛在的安全風(fēng)險(xiǎn)。首先,服務(wù)器會完全開放,允許后端服務(wù)調(diào)用應(yīng)用中的任何JS。
不受我們控制的外部站點(diǎn)(或者蓄意攻擊者)可以隨時更改腳本,使我們的整個站點(diǎn)變得脆弱。 服務(wù)器或中間人有可能會將額外的JS邏輯返回給頁面,從而將用戶的隱私數(shù)據(jù)暴露出來。

使用CORS

CORS規(guī)范簡單地?cái)U(kuò)展了標(biāo)準(zhǔn)的XHR對象,以允許JS發(fā)送跨域的XHR請求。它會通過預(yù)檢查來確認(rèn)是否有權(quán)限向目標(biāo)服務(wù)器發(fā)送請求。
預(yù)檢查可以讓服務(wù)器接受或拒絕來自全部服務(wù)器、特定服務(wù)器或一組服務(wù)器的請求。這意味著客戶端和服務(wù)端應(yīng)用需要協(xié)同工作,才能向客戶端或服務(wù)器發(fā)送數(shù)據(jù)。

設(shè)置

為了使用CORS,首先需要告訴AngularJS我們正在使用CORS。使用config()方法在應(yīng)用模塊上設(shè)置兩個參數(shù)以達(dá)到此目的。
首先,告訴AngularJS使用XDomain,并從所有的請求中把X-Request-With頭移除掉。X-Request-With頭默認(rèn)就是移除掉的,但是再次確認(rèn)它已經(jīng)被移除沒有壞處。

angular.module('myApp', []) 
.config(function($httpProvider) { 
    $httpProvider.defaults.useXDomain = true; 
    delete $httpProvider.defaults.headers 
        .common['X-Requested-With'];
});

現(xiàn)在可以發(fā)送CORS請求了。

服務(wù)器端CORS支持

確保服務(wù)器支持CORS是很重要的。支持CORS的服務(wù)器必須在響應(yīng)中加入幾個訪問控制相關(guān)的頭。

  • Access-Control-Allow-Origin
    這個頭的值可以是與請求頭的值相呼應(yīng)的值,也可以是*,從而允許接收從任何來源發(fā)來的請求。
  • Access-Control-Allow-Credentials(可選)
    默認(rèn)情況下,CORS請求不會發(fā)送cookie。如果服務(wù)器返回了這個頭,那么就可以通過將withCredentials設(shè)置為true來將cookie同請求一同發(fā)送出去。
    如果將$http發(fā)送的請求中的withCredentials設(shè)置為true,但服務(wù)器沒有返回Access-Control-Allow-Credentials,請求就會失敗,反之亦然。 后端服務(wù)器必須能處理OPTIONS方法的HTTP請求。

CORS請求分為簡單和非簡單兩種類型。

簡單請求

如果請求使用HEAD、GET、POST中的一種HTTP方法就是簡單請求。
如果請求除了下面列表中的一個或多個HTTP頭以外,沒有使用其他頭:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type
    • application/x-www-form-urlencoded
    • multipart/form-data;
    • text/plain

我們把這類請求歸類為簡單請求,因?yàn)闉g覽器可以不需要使用CORS就發(fā)送這類請求。簡單請求不要求瀏覽器和服務(wù)器之間有任何的特殊通信。

$http.get("https://api.github.com").success(function(data) { 
    // 數(shù)據(jù)
});

非簡單請求

不符合簡單請求標(biāo)準(zhǔn)的請求被稱為非簡單請求。如果想要支持PUT或DELETE方法,又或者想給請求設(shè)置特殊的內(nèi)容類型,就需要發(fā)送非簡單請求。
盡管這些請求在客戶端開發(fā)者看來沒什么不同,但瀏覽器會以不同的方式處理它們。瀏覽器實(shí)際上會發(fā)送兩個請求:預(yù)請求和請求。瀏覽器首先會向服務(wù)器發(fā)送預(yù)請求來獲得發(fā)送請求的許可,只有許可通過了,瀏覽器才會發(fā)送真正的請求。
瀏覽器處理CORS的過程是透明的。同簡單請求一樣,瀏覽器會給預(yù)請求和請求都加上Origin頭。

預(yù)請求

瀏覽器發(fā)送的預(yù)請求是OPTIONS類型的,預(yù)請求中包含以下頭信息:

  • Access-Control-Request-Method
    這個頭是請求所使用的HTTP方法,會始終包含在請求中。
  • Access-Control-Request-Headers(可選)
    這個頭的值是一個以逗號分隔的非簡單頭列表,列表中的每個頭都會包含在這個請求中。服務(wù)器必須接受這個請求,然后檢查HTTP方法和頭的合法性。如果通過了檢查,服務(wù)器會在響應(yīng)中添加下面這個頭:
  • Access-Control-Allow-Origin
    這個頭的值必須和請求的來源相同,或者是*符號,以允許接受來自任何來源的請求。
  • Access-Control-Allow-Methods
    這是一個可以接受的HTTP方法列表,對在客戶端緩存響應(yīng)結(jié)果很有幫助,并且未來發(fā)送的請求可以不必總是發(fā)送預(yù)請求。
  • Access-Control-Allow-Headers
    如果設(shè)置了Access-Control-Request-Headers頭,服務(wù)器必須在響應(yīng)中添加同一個頭。
    我們希望服務(wù)器在可以接受這個請求時返回200狀態(tài)碼。如果服務(wù)器返回了200狀態(tài)碼,真正的請求才會發(fā)出。

CORS并不是一個安全機(jī)制,只是現(xiàn)代瀏覽器實(shí)現(xiàn)的一個標(biāo)準(zhǔn)。AngularJS中的非簡單請求與普通請求看起來沒有什么區(qū)別。

$http.delete("https://api.github.com/api/users/1").success(function(data) {
    // 數(shù)據(jù)
});

服務(wù)器端代理

實(shí)現(xiàn)向所有服務(wù)器發(fā)送請求的最簡單方式是使用服務(wù)器端代理。這個服務(wù)器和頁面處在同一個域中(或者不在同一個域中但支持CORS),做為所有遠(yuǎn)程資源的代理。
可以簡單地通過使用本地服務(wù)器來代替客戶端向外部資源發(fā)送請求,并將響應(yīng)結(jié)果返回給客戶端。通過這種方式,老式瀏覽器不必使用需要發(fā)送額外請求的CORS(只有現(xiàn)代瀏覽器支持CORS)也能發(fā)送跨域請求,并且可以在瀏覽器中采用標(biāo)準(zhǔn)的安全策略。
為了實(shí)現(xiàn)服務(wù)器端代理,需要架設(shè)一個本地服務(wù)器來處理我們所有的請求,并負(fù)責(zé)向第三方發(fā)送實(shí)際的請求。

使用 JSON

JSON是JavaScript Object Notation的簡寫,是一種看起來像JS對象的數(shù)據(jù)交換格式。事實(shí)上,當(dāng)JS加載它時,它確實(shí)會被當(dāng)做一個對象來解析。AngularJS也會將所有以JSON格式返回的JS對象解析為一個與之對應(yīng)的Angular對象。例如,如果服務(wù)器返回以下JSON:

[
    {"msg": "This is the first msg", state: 1}, 
    {"msg": "This is the second msg", state: 2}, 
    {"msg": "This is the third msg", state: 1}, 
    {"msg": "This is the fourth msg", state: 3}
]

當(dāng)AngularJS通過$http服務(wù)收到這個數(shù)據(jù)后,可以像普通JS對象那樣來引用其中的數(shù)據(jù)。

$http.get('/v1/messages.json').success(function(data,status) { 
    $scope.first_msg = data[0].msg; 
    $scope.first_state = data[0].state; 
});

使用AngularJS進(jìn)行身份驗(yàn)證

服務(wù)器端需求

首先必須保證服務(wù)器端API的安全性。下面是常被用來保護(hù)客戶端應(yīng)用的兩種方法。

1.服務(wù)器端視圖渲染

如果站點(diǎn)所有的HTML頁面都是由后端服務(wù)器處理的,可以使用傳統(tǒng)的授權(quán)方式,由服務(wù)器
端進(jìn)行鑒權(quán),只發(fā)送客戶端需要的HTML。

2.純客戶端身份驗(yàn)證

我們希望客戶端和服務(wù)端的開發(fā)工作可以解耦并各自獨(dú)立進(jìn)行,且可以將組件獨(dú)立地發(fā)布到生產(chǎn)環(huán)境中,互相沒有影響。因此,需要通過使用服務(wù)器端API來保護(hù)客戶端身份驗(yàn)證的安全, 但并不依賴這些API來進(jìn)行身份驗(yàn)證。
通過令牌授權(quán)來實(shí)現(xiàn)客戶端身份驗(yàn)證,服務(wù)器需要做的是給客戶端應(yīng)用提供授權(quán)令牌。令牌本身是一個由服務(wù)器端生成的隨機(jī)字符串,由數(shù)字和字母組成,它與特定的用戶會話相關(guān)聯(lián)。uuid庫是用來生成令牌的好選擇。
當(dāng)用戶登錄到我們的站點(diǎn)后,服務(wù)器會生成一個隨機(jī)的令牌,并將用戶會話同令牌之間建立關(guān)聯(lián),用戶無需將ID或其他身份驗(yàn)證信息發(fā)送給服務(wù)器。
客戶端發(fā)送的每個請求都應(yīng)該包含此令牌,這樣服務(wù)器才能根據(jù)令牌來對請求的發(fā)送者進(jìn)行身份驗(yàn)證。
服務(wù)器端則無論請求是否合法,都會將對應(yīng)事件的狀態(tài)碼返回給客戶端,這樣客戶端才能做出響應(yīng)。
例如,我們希望服務(wù)端對所有身份驗(yàn)證未通過的請求都返回401狀態(tài)碼。下面是一些常用的狀態(tài)碼:


當(dāng)客戶端收到這些狀態(tài)碼時會做出相應(yīng)的響應(yīng)。
數(shù)據(jù)流程如下:
(1)一個未經(jīng)過身份驗(yàn)證的用戶瀏覽了我們的站點(diǎn);
(2)用戶試圖訪問一個受保護(hù)的資源,被重定向到登錄頁面,或者用戶手動訪問了登錄頁面;
(3)用戶輸入了他的登錄ID(用戶名或電子郵箱)以及密碼,接著AngularJS應(yīng)用通過POST請求將用戶的信息發(fā)送給服務(wù)端;
(4)服務(wù)端對ID和密碼進(jìn)行校驗(yàn),檢查它們是否匹配;
(5)如果ID和密碼匹配,服務(wù)端生成一個唯一的令牌,并將其同一個狀態(tài)碼為200的響應(yīng)一起返回。如果ID和密碼不匹配,服務(wù)器返回一個狀態(tài)碼為401的響應(yīng)。
對一個已經(jīng)通過身份驗(yàn)證的用戶(通過了上面5個步驟的用戶),流程如下:
(1) 用戶請求一個受保護(hù)的資源路徑(比如他自己的賬號頁面);
(2) 如果用戶尚未登錄,應(yīng)用會將他重定向到登錄頁面。如果用戶登錄了,應(yīng)用會使用該會話對應(yīng)的令牌來發(fā)送請求;
(3) 服務(wù)器對令牌進(jìn)行校驗(yàn),并根據(jù)請求返回合適的數(shù)據(jù)。

客戶端身份驗(yàn)證

身份驗(yàn)證機(jī)制需要處理的一些行為

  • 重定向未經(jīng)過身份驗(yàn)證的頁面請求
  • 捕獲所有響應(yīng)狀態(tài)碼非200的XHR請求,并進(jìn)行相應(yīng)的處理
  • 在整個頁面會話中持續(xù)監(jiān)視用戶的身份驗(yàn)證情況

為了對未通過驗(yàn)證的用戶訪問受保護(hù)資源的行為進(jìn)行重定向,需要能夠?qū)操Y源和受保護(hù)資源進(jìn)行區(qū)分。
有下面幾種方法可以將路由定義為公共或非公共。

1.保護(hù)API訪問的資源

如果想要對一個會發(fā)送受保護(hù)的API請求(例如,一個服務(wù)器可能返回401狀態(tài)碼的API請求)的路由進(jìn)行保護(hù),但又希望可以正常加載頁面,可以簡單地通過$http攔截器來實(shí)現(xiàn)。
想要創(chuàng)建一個$http攔截器并能夠處理未通過身份驗(yàn)證的API請求,首先要創(chuàng)建一個攔截器來處理所有的響應(yīng)。
現(xiàn)在,我們在應(yīng)用的.config()代碼塊內(nèi)設(shè)置$http響應(yīng)攔截器,并將$httpProvider注入其中。這個攔截器會處理所有請求的響應(yīng)以及響應(yīng)錯誤。

angular.module('myApp', [])
.config(function($httpProvider) {
    // 在這里構(gòu)造攔截器
    var interceptor = function($q, $rootScope, Auth) {
        return {
            'response': function(resp) {
                if (resp.config.url == '/api/login') { 
                    // 假設(shè)API服務(wù)器返回的數(shù)據(jù)格式如下: 
                    // { token: "AUTH_TOKEN" } 
                    Auth.setToken(resp.data.token);
                }
                return resp;
            },
            'responseError': function(rejection) {
                // 錯誤處理
                switch(rejection.status) {
                case 401:
                    if (rejection.config.url!=='api/login') 
                        // 如果當(dāng)前不是在登錄頁面 
                        $rootScope.$broadcast('auth:loginRequired'); 
                    break;
                case 403: 
                    $rootScope.$broadcast('auth:forbidden'); 
                    break;
                case 404: 
                    $rootScope.$broadcast('page:notFound'); 
                    break;
                case 500: 
                    $rootScope.$broadcast('server:error'); 
                    break;
                }
                return $q.reject(rejection);
            }
        };
    };
});

這個授權(quán)攔截器會處理特定請求中一些可預(yù)見的服務(wù)器響應(yīng)狀態(tài)碼。當(dāng)攔截器捕獲到401狀態(tài)碼,會通過$broadcasts$rootScope開始向所有的子作用域廣播此事件。另外,攔截器會為任何返回200狀態(tài)碼的請求將令牌保存到/api/login登錄路由中。
為了實(shí)現(xiàn)這個攔截器,需要讓$httpProvider將這個攔截器添加到攔截器鏈中。

angular.module('myApp', []) 
.config(function($httpProvider) {
    // 在這里構(gòu)造攔截器
    var interceptor = function($q, $rootScope, Auth) {
     // ...
    };
    // 將攔截器和$http的request/response鏈整合在一起 
    $httpProvider 
    .interceptors.push(interceptor);
});
2.使用路由定義受保護(hù)資源

如果我們希望始終對某些路徑進(jìn)行保護(hù),或者請求的API不會對路由進(jìn)行保護(hù),那就需要監(jiān)視路由的變化,以確保訪問受保護(hù)路由的用戶是處于登錄狀態(tài)的。為了監(jiān)視路由變化,需要為$routeChangeStart事件設(shè)置一個事件監(jiān)聽器。這個事件會在路由屬性開始resolve時觸發(fā),但此時路由還沒有真的發(fā)生變化。
通過同攔截器協(xié)同工作,這種方式會更加有效。如果不通過攔截器檢查狀態(tài)碼, 用戶依然有可能發(fā)送未經(jīng)授權(quán)的請求。
通過監(jiān)聽器對事件進(jìn)行監(jiān)聽,并檢查路由,看它是否定義為可被當(dāng)前用戶訪問。首先要定義應(yīng)用的訪問規(guī)則??梢酝ㄟ^在應(yīng)用中設(shè)置常量,然后在每個路由中通過對比這些常量來判斷用戶是否具有訪問權(quán)限。

angular.module('myApp', ['ngRoute']) 
.constant('ACCESS_LEVELS', {
    pub: 1,
    user: 2
});

通過把ACCESS_LEVELS設(shè)置為常量,可以將它注入到.confgi().run()代碼塊中,并在整個應(yīng)用范圍內(nèi)使用。下面,使用這些常量來為每個路由都定義訪問級別:

angular.module('myApp', ['ngRoute']) 
.config(function($routeProvider, ACCESS_LEVELS) { 
    $routeProvider
        .when('/', {
            controller: 'MainController', 
            templateUrl: 'views/main.html', 
            access_level: ACCESS_LEVELS.pub 
        })
        .when('/account', {
            controller: 'AccountController', 
            templateUrl: 'views/account.html', 
            access_level: ACCESS_LEVELS.user 
        })
        .otherwise({
            redirectTo: '/'
        });
});

上面每一個路由都定義了自身的access_level,可以根據(jù)這一點(diǎn)判斷當(dāng)前用戶的授權(quán)狀態(tài), 以及用戶的級別是否有權(quán)限訪問當(dāng)前路由。
此時,用戶可能處于以下兩種狀態(tài):

  • 未經(jīng)過身份驗(yàn)證的匿名用戶;
  • 通過身份驗(yàn)證的已知用戶。

為了驗(yàn)證用戶的身份,需要創(chuàng)建一個服務(wù)來對已經(jīng)存在的用戶進(jìn)行監(jiān)視。同時需要讓服務(wù)能夠訪問瀏覽器的cookie,這樣當(dāng)用戶重新登錄時,只要會話有效就無需再次進(jìn)行身份驗(yàn)證。 這個小服務(wù)包含了一些操作用戶對象的輔助函數(shù)。

angular.module('myApp.services', [])
.factory('Auth',  function($cookieStore,ACCESS_LEVELS) { 
    var _user = $cookieStore.get('user');
    var setUser = function(user) { 
        if (!user.role || user.role < 0) { 
            user.role = ACCESS_LEVELS.pub; 
        }
        _user = user; 
        $cookieStore.put('user', _user); 
    };
    return {
        isAuthorized: function(lvl) { 
            return _user.role >= lvl; 
        },
        setUser: setUser,
        isLoggedIn: function() { 
            return _user ? true : false; 
        },
        getUser: function() { 
            return _user;
        },
        getId: function() {
            return _user ? _user._id : null; 
        },
        getToken: function() { 
            return _user ? _user.token : ''; 
        },
        logout: function() { 
            $cookieStore.remove('user'); 
            _user = null; }
        }
    };
});

現(xiàn)在,當(dāng)用戶已經(jīng)通過身份驗(yàn)證并登錄后,可以在$routeChangeStart事件中對其有效性進(jìn)行檢查。

angular.module('myApp', [])
.run(function($rootScope, $location, Auth) {
    // 給$routeChangeStart設(shè)置監(jiān)聽 
    $rootScope.$on('$routeChangeStart', function(evt, next, curr) {

        if (!Auth.isAuthorized(next.$$route.access_level)) {
 if (Auth.isLoggedIn()) { 
                // 用戶登錄了,但沒有訪問當(dāng)前視圖的權(quán)限 
                $location.path('/');
            } else { 
                $location.path('/login');
            }
        }
    });
});
3.發(fā)送經(jīng)過身份驗(yàn)證的請求

當(dāng)我們通過了身份驗(yàn)證,并取回了用戶的授權(quán)令牌后,就可以在向服務(wù)器發(fā)送請求時使用令牌。從服務(wù)器的角度看,當(dāng)收到一個帶有令牌的請求時,驗(yàn)證令牌的有效性是服務(wù)器的責(zé)任之一。
如果提供的令牌是合法的,且與一個合法用戶是關(guān)聯(lián)的狀態(tài),那服務(wù)器就會認(rèn)為用戶的身份是合法且安全的。
通過令牌進(jìn)行身份驗(yàn)證的安全性取決于通信所采用的通道,因此盡可能地使用SSL連接可以提高安全性。
如果用戶已經(jīng)通過了身份驗(yàn)證,可以在發(fā)送請求時單獨(dú)給每個請求都加入驗(yàn)證信息,或者把令牌附加到所有的請求中。
手動使用身份令牌 手動創(chuàng)建一個可以發(fā)送令牌的請求,只要將token當(dāng)作參數(shù)或請求頭添加到請求中即可。例如,如果我們想對服務(wù)器發(fā)出一個請求,此時我們正在這個服務(wù)器上通過Backend服務(wù)請求用戶分析數(shù)據(jù)。

angular.module('myApp', [])
.service('Backend', function($http, $q, $rootScope, Auth) { 
    this.getDashboardData = function() {
        $http({
            method: 'GET',
            url: 'http://myserver.com/api/dashboard' 
        }).success(function(data) {
            return data.data; 
        }).catch(function(reason) { 
            $q.reject(reason);
        });
    };
});

簡單地將token當(dāng)作參數(shù)(或請求頭)發(fā)送就可以進(jìn)行令牌驗(yàn)證。

angular.module('myApp', [])
.service('Backend', function($http, $q, $rootScope, Auth) { 
    this.getDashboardData = function() {
        $http({
            method: 'GET',
            url: 'http://myserver.com/api/dashboard', 
            params: {
                token: Auth.getToken() 
        }).success(function(data) {
            return data.data; 
        }).catch(function(reason) { 
            $q.reject(reason);
        }); 
    };
});

當(dāng)向后端發(fā)送請求時,請求會被添加token參數(shù)。
自動添加身份令牌更進(jìn)一步,如果想要為每個請求都添加上當(dāng)前用戶的令牌,可以創(chuàng)建一個請求攔截器,并將令牌當(dāng)作參數(shù)添加進(jìn)請求中。

angular.module('myApp', []) 
.config(function($httpProvider) {
    // 在這里構(gòu)造攔截器
    var interceptor = function($q, $rootScope, Auth) { 
        return {
            'request': function(req) { 
                return req;
            },
            'requestError': function(reqErr) { 
                return reqErr;
            }
        };
    };
});

在請求攔截器內(nèi)部可以加入向請求中添加token參數(shù)的業(yè)務(wù)邏輯,通過用戶是否持有令牌來檢查身份驗(yàn)證情況,同時需要確保不會將手動添加的同名參數(shù)覆蓋。

function($q, $rootScope, Auth) {
    return {
        'request': function(req) {
            req.params = req.params || {};
            if (Session.isAuthenticated() && !req.params.token) { 
                req.params.token = Auth.getToken();
            }
            return req;
        },
        // ...
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • $http 我們可以使用內(nèi)置的$http服務(wù)直接同外部進(jìn)行通信。$http服務(wù)只是簡單的封裝了瀏覽器原生的XMLH...
    oWSQo閱讀 760評論 0 0
  • API定義規(guī)范 本規(guī)范設(shè)計(jì)基于如下使用場景: 請求頻率不是非常高:如果產(chǎn)品的使用周期內(nèi)請求頻率非常高,建議使用雙通...
    有涯逐無涯閱讀 2,928評論 0 6
  • 我曾經(jīng)看過這樣一個故事: 羅斯是耶魯大學(xué)一名剛畢業(yè)的大學(xué)生,他在冬季的征兵中依法被征,即將到最艱苦危險(xiǎn)的美國海軍陸...
    我是一小白白閱讀 410評論 3 2
  • 同樣是寫戍卒思鄉(xiāng),《采薇》里的士卒就沒有可以思念的妻子了,在外族入侵之時,陪伴他們的只有虛無飄渺的大局觀、大體觀,...
    王家人寧閱讀 235評論 0 0

友情鏈接更多精彩內(nèi)容