0

我有一個主幹應用程序,我使用dualStorage並且還爲Backbone實現了自己的同步。我已經實現了我自己的同步,因爲在我的API中,它需要在每個請求的標頭中發送身份驗證令牌。如果此身份驗證令牌不存在或無效,則API會返回401錯誤。Backbone.Sync與Safari的問題

我的應用程序有兩個選項卡,當您單擊其中一個或將路由從/#guestlist切換到/#ticketlist時,反之亦然。只有在切換選項卡時纔會發生此問題,而不是在應用程序中轉到任何其他路由時。這個問題讓我非常奇怪,只有這兩個請求失敗,所有的同步操作都應該被覆蓋。

我現在所遇到的問題似乎只存在於Safari中,並未出現在Chrome或Firefox中,但是由於這種情況主要在iPad上運行,因此我不能忽略此問題。

這裏就在眼前

1)登錄到系統中的問題,一切都很正常UI從API數據 2)點擊票務列表選項卡,系統會將您註銷填充。這是因爲API(僅在野生動物園再次)返回401作爲驗證令牌不存在在請求

[Error] Failed to load resource: the server responded with a status of 401 (Unauthorized) (ticketlist, line 0) 

下面是我對Backbone.sync代碼。

/* 
* Store a version of Backbone.sync to call from the 
* modified version we create 
*/ 
var _nativeSync = Backbone.sync; 

Backbone.sync = function (method, model, options) { 
    /* 
    * The jQuery `ajax` method includes a 'headers' option 
    * which lets you set any headers you like 
    */ 

    if(CheckinApp.getSession().isAuthenticated() !== false) { 
     /* 
     * Set the 'Authorization' header and get the access 
     * token from the `auth` module 
     */ 
     options.headers = { 
      'Authorization': 'Token ' +  CheckinApp.getSession().getAuthorizationToken() 
     } 

    } 

    /* 
    * Call the stored original Backbone.sync method with 
    * extra headers argument added 
    */ 
    _nativeSync(method, model, options); 
}; 

我唯一擔心的是,也許這正從使用dualStorage的衝突,因爲我知道,也覆蓋了Backbone.sync方法。爲了得到這個工作,我必須在dualStorage之後包含我的同步,如下所示。

<script type="text/javascript" src="js/vendor/backbone.dualstorage.min.js"></script> 
<script type="text/javascript" src="js/plugins/backbone.sync.js"></script> 

我也甩了標題爲在API方面的要求,並可以看到授權令牌丟失這個特殊請求從Safari瀏覽器正在進行時,而不是在通過Chrome或Firefox提出同樣的要求。

[Tue Apr 07 14:49:08.677473 2015] [:error] [pid 16743] [client 71.181.125.154:64016] <pre>Array\n(\n  
[Host] => jcrawford.heytix.com\n  
[User-Agent] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.78.2 (KHTML, like Gecko) Version/6.1.6 Safari/537.78.2\n  
[Accept] => application/json, text/javascript, */*; q=0.01\n [ 
Referer] => http://jcrawford.heytix.com/guestlist/\n  
[X-Requested-With] => XMLHttpRequest\n  
[Authorization] => Token 951ba59c833a80e4ddaf72ee6b3d9143\n  
[Accept-Language] => en-us\n [Accept-Encoding] => gzip, deflate\n  
[Cookie] => 'removed from output'  
[Connection] => keep-alive\n)\n</pre>, referer: http://jcrawford.heytix.com/guestlist/ 

[Tue Apr 07 14:49:12.027279 2015] [:error] [pid 16743] [client 71.181.125.154:64016] <pre>Array\n(\n  
[Host] => jcrawford.heytix.com\n  
[User-Agent] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.78.2 (KHTML, like Gecko) Version/6.1.6 Safari/537.78.2\n  
[Accept] => application/json, text/javascript, */*; q=0.01\n  
[Referer] => http://jcrawford.heytix.com/guestlist/\n  
[Accept-Encoding] => gzip, deflate\n  
[X-Requested-With] => XMLHttpRequest\n  
[Accept-Language] => en-us\n  
[Cookie] => 'removed from output' 
[Connection] => keep-alive\n)\n</pre>, referer: http://jcrawford.heytix.com/guestlist/ 

[Tue Apr 07 14:49:12.027565 2015] [:error] [pid 16743] [client 71.181.125.154:64016] HTTP 401 (GET /api/events/13044/guestlist), referer: http://jcrawford.heytix.com/guestlist/ 

這就是我用鉻和/或Firefox獲得的。

[Tue Apr 07 14:57:38.686859 2015] [:error] [pid 17630] [client 71.181.125.154:65109] <pre>Array\n(
[Host] => jcrawford.heytix.com 
[Connection] => keep-alive 
[Cache-Control] => max-age=0 
[Accept] => application/json, text/javascript, */*; q=0.01 
[X-Requested-With] => XMLHttpRequest 
[User-Agent] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36 
[Authorization] => Token 951ba59c833a80e4ddaf72ee6b3d9143 
[Referer] => http://jcrawford.heytix.com/guestlist/ 
[Accept-Encoding] => gzip, deflate, sdch 
[Accept-Language] => en-US,en;q=0.8 
[Cookie] => 'removed from output' 
)</pre>, referer: http://jcrawford.heytix.com/guestlist/ 


[Tue Apr 07 14:57:44.001465 2015] [:error] [pid 17492] [client 71.181.125.154:65106] <pre>Array\n(\n  
[Host] => jcrawford.heytix.com\n  
[Connection] => keep-alive\n  
[Accept] => application/json, text/javascript, */*; q=0.01\n  
[X-Requested-With] => XMLHttpRequest\n  
[User-Agent] => Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36\n 
[Authorization] => Token 951ba59c833a80e4ddaf72ee6b3d9143\n  
[Referer] => http://jcrawford.heytix.com/guestlist/\n  
[Accept-Encoding] => gzip, deflate, sdch\n 
[Accept-Language] => en-US,en;q=0.8\n  
[Cookie] => 'removed from output' 
)\n</pre>, referer: http://jcrawford.heytix.com/guestlist/ 

你可以從授權令牌上面記錄看到的是通過與Firefox/Chrome,但不能與Safari瀏覽器通過。我已將日誌記錄添加到sync方法,並且在查詢API之前在控制檯中聲明用戶已通過身份驗證,然後重定向到登錄頁面。

我沒有看到在Safari開發工具/控制檯等任何其他錯誤或任何應用發出請求到API,得到一個401(如預期無令牌),然後記錄用戶退出Backbone App並重定向到登錄頁面。當沒有令牌存在時,這種行爲是預期的問題是爲什麼這不會通過令牌通過這些特定的路線?只有這些路線導致了問題,所有其他路線似乎在用戶界面中工作得很好。

我也將提供我的路由器,以便您可以看到發生了什麼,請記住我使用事件來做大部分的實際路由,所以如果您需要查看任何其他代碼,請讓我知道。

CheckinApp.Routers.Default = Backbone.Router.extend({ 
    view: null, 

    public_routes: ['login'], 

    routes:{ 
     "":"eventlist", 
     "login": "login", 
     "guestlist": "guestlist", 
     "ticketlist":"ticketlist", 
     "managerslist":"managerslist", 
     "events": "eventlist", 
     "organize(/)(:action)": "displayOrganize", 
     "eventreport(/)(:event_id)": "eventreport", 
     "venuereport(/)(:venue_name)": "venuereport" 
    }, 

    initialize:function (options) { 
     this.view = options.view; 
     Backbone.history.start(); 
    }, 

    guestlist:function() { 
     CheckinApp.getVent().trigger('main:renderListView', {title: 'Guest List', type: 'ticket', tab_hash: '#guestlist'}); 
    }, 
    ticketlist:function() { 
     CheckinApp.getVent().trigger('main:renderListView', {title: 'Ticket List', type: 'ticket', tab_hash: '#ticketlist'}); 
    }, 
    managerslist:function() { 
     CheckinApp.getVent().trigger('main:renderListView', {title: 'Managers List', type: 'ticket', tab_hash: '#managerslist'}); 
    }, 
    eventlist: function() { 
     var vent = CheckinApp.getVent(); 
     vent.trigger('main:renderListView', {title: 'Todays Events', type: 'event'}); 
     vent.trigger('tabs:remove'); 
    }, 
    eventreport: function() { 
     var collection = new CheckinApp.Collections.EventReport({"event_id": 13044}); 
     var view = new CheckinApp.Views.EventReport({collection: collection}); 
     view.render(); 
    }, 
    venuereport: function(venue_name) { 
     var collection = new CheckinApp.Collections.VenueReport([], {"venue_name": 'borgata'}); 
     var view = new CheckinApp.Views.VenueReport({collection: collection}); 
     var modal = new Backbone.BootstrapModal({ 
      content: view, 
      title: ' ', 
      animate: true 
     }); 
     modal.open(); 
     //view.render(); 
    }, 

    login: function() { 
     var view = new CheckinApp.Views.Login({}); 
     view.render(); 
    }, 

    before: function (route, params) { 

     if($.cookie('CheckinApp') && CheckinApp.getSession().isAuthenticated() == false) { 
      CheckinApp.setSessionFromCookie(JSON.parse($.cookie('CheckinApp'))); 
     } 
     var hasAccess = CheckinApp.getSession().isAuthenticated(); // If cookie exists they are logged in.. 

     if (!hasAccess) { 
      this.navigate('login', true); 
     } else { 
      if(route == 'login') { 
       this.navigate('', true); 
       return false; 
      } 
     } 
     if((_.contains(this.public_routes, route) === false)) { 
      return hasAccess; //return true if you want to proceed to routes else return false 
     } 
    }, 

    after: function(route, params) { 
     if(route == 'logout') return false; 
     else { 
      CheckinApp.updateCookie(); 
      return true; 
     } 
    } 
}); 

最後,這是告訴jQuery監聽401並註銷用戶的代碼。

$.ajaxSetup({ 
    statusCode: { 
     401: function() { 
      CheckinApp.clearSession(); 
      Backbone.history.navigate('#login', true); 
     } 
    } 
}); 

我還採取了這一步,並添加了一堆console.log語句前的路線,並提出了這一點。看起來,這些特定的路由可能正在做某些事情,導致身份驗證丟失?

[Log] sync : isAuthenticated = true (backbone.sync.js, line 12) 
[Log] sync: url = http://jcrawford.heytix.com/guestlist/checkin/api/events/13044/guestlist/ (backbone.sync.js, line 13) 
[Error] Failed to load resource: the server responded with a status of 401 (Unauthorized) (guestlist, line 0) 
[Log] before : isAuthenticated: false (default.js, line 60) 
[Log] cookie: undefined (default.js, line 61) 
[Log] before : hasAccess = false (default.js, line 66) 
[Log] before : hasAccess = false, going to login page (default.js, line 68) 
[Log] before : going to route login (default.js, line 76) 

正如你可以使該數據AJAX請求前行看到它說驗證,那麼請求失敗,它說,未通過身份驗證。

這裏是一個比較日誌從我的同步方法,這時候

sync : isAuthenticated = true (backbone.sync.js, line 12) 
sync: url = http://jcrawford.heytix.com/guestlist/checkin/api/events/13044/guestlist/ (backbone.sync.js, line 13) 
User is Authenticated (backbone.sync.js, line 15) 
options: {"parse":true,"headers":{"Authorization":"Token 951ba59c833a80e4ddaf72ee6b3d9143"}} (backbone.sync.js, line 24) 

正如你可以看到上面的選項都在頭部,但由於某種原因,使用Safari骨架沒有發送這些報頭與時被設置同步請求。

每一個建議(和下面的一個)我試圖修改我的$ .ajaxSetup的jQuery,但我收到了完全相同的結果,因爲我目前遇到。

$.ajaxSetup({ 
    headers: function() { 
     var token = ''; 
     if(CheckinApp) { 
      var session = CheckinApp.getSession(); 
      if(session) { 
       token = CheckinApp.getSession().getAuthorizationToken(); 
      } 
     } 
     return { 
      "Authorization": "Token " + token 
     }; 
    }, 
    statusCode: { 
     401: function() { 
      CheckinApp.clearSession(); 
      Backbone.history.navigate('#login', true); 
     } 
    } 
}); 

任何援助將不勝感激。

回答

1

,因爲我的門票收藏網址中包含一個尾隨/

隨着尾隨/替代Safari瀏覽器將發出一個飛行前的請求URL與這個問題發生的事情承擔全部尾隨斜線並收到302 Found。然後,它將向URI發出請求,而不會收到尾部斜槓,並接收401,而不是授權令牌傳遞給API的第二個請求。

我不太確定這是Backbone還是jQuery的問題,但無論哪種方式似乎都不像尾隨斜槓那樣去除它解決了Safari問題。

0

您是否試圖直接使用$.ajaxSetup()令牌並查看是否可以通過Safari瀏覽器複製相同的問題?你的例子不知道你的路由器如何調用beforeafter函數,但看起來你可以在那裏設置ajax設置,因爲你已經檢查了hasAccess()。

例如:

$.ajaxSetup({ 
    headers: { 'Authorization' : 'Token ' + howeverYouGetToken() } 
}); 
+0

我也試過,它對我來說工作不正常,它提供了與我現在遇到的相同的問題。 – 2015-04-07 15:04:13

+0

解決方案被發現並在下面發佈,僅供參考。 – 2015-04-07 17:47:00