2016-01-10 48 views
-1

我在Express(Node)服務器應用程序中有一個複雜的承諾用例,現在我被要求將此服務器遷移到Django。基本上我的服務器(我們稱之爲「A」)是另一臺服務器(我們稱之爲「B」)的OAuth2客戶端,因此A可以通過B的API請求資源。同樣,服務器A提供了它自己的API,這個API是通過瀏覽器中的javascript代碼通過ajax來使用的。讓我告訴你下面的圖片,以使事情更清楚:enter image description hereDjango等效於Node.js的藍鳥承諾

我的服務器A像瀏覽器和服務器B之間的中間件一樣工作。所以當瀏覽器打電話給A的API函數之一時,A又會使多次調用B的API並基於這些結果A將自己的東西返回給瀏覽器。

所以,在代碼方面,我是做的Node.js這樣的事情(代碼只是一個簡化):

var express = require('express'); 
var router = express.Router(); 
var request = require('request-promise'); 
var Promise = require('bluebird'); 
... 

//the following are helper functions 

function getStuff1(req,res,params) { 
    request.get({ 
     uri: "http://externalserver.com/api/whatever...", 
     headers: { 
      'Authorization':'Bearer' + req.user.accessToken //<-- notice that I'm using the user's access token (OAuth2) 
     } 
    }).then(function(input) { 
     //use params and input and compute stuff 
     return stuff; 
    }).catch(function(error) { 
     if(error.statusCode == 401) { // the accessToken has expired, we need to refresh it 
      return refreshOAuthToken(req,res) 
       .then(function(){ 
        return getStuff1(req,res,params); // after refreshing the accessToken, we recursively call getStuff1 again 
       }) 
       .catch(function(err) { 
        throw(err); 
       }); 
     } else { 
      throw(error); 
     } 
    }); 
} 

function getStuff2(req,res,params) { ... } 
function getStuff3(req,res,params) { ... } 
function getStuff4(req,res,params) { ... } 
... 

function refreshOAuthToken(req,res) { 

    return request.post({ 
     uri: "http://otherserver/oauth/token", 
     form: { 
      'client_id': oauthClientId, 
      'client_secret': oauthClientSecret, 
      'grant_type': 'refresh_token', 
      'refreshToken': req.user.refreshToken // we're using the user's refresh token 
     }) 
     .then(function(body) { 
      jsonResponse = JSON.parse(body); 
      req.user.accessToken = jsonResponse.access_token; 
      req.user.refreshToken = jsonResponse.refresh_token;  
     }) 
     .catch(function(error) { 
      throw(error); 
     }); 
    }; 
} 

// the following is an actual API function 

function apiFunction1(req,res) { 

    //first we compute params1 somehow 
    var params1 = req.whatever; 

    getStuff1(req,res, params1) 
    .then(function(stuff1) { 
     // do something with stuff1 and compute params2 
     return getStuff2(req,res,params2); 
    }) 
    .then(function(stuff2) { 
     // do something with stuff2 and compute params3 
     return getStuff3(req,res,params3); 
    }) 
    .then(function(stuff3) { 
     // now make 2 asynchronous calls at the same time 
     var promise4 = getStuff4(req,res,params4); 
     var promise5 = getStuff5(req,res,params5); 
     return Promise.all([promise4,promise5]); //we combine 2 promises into 1 with Promise.all 
    }) 
    .then(function(results) { 
     var stuff4 = results[0]; 
     var stuff5 = results[1]; 

     //do something with stuff4 and stuff5, and compute the final answer 
     var answer = doSomethingWith(stuff4,stuff5); 

     res.send(answer); //finally we send the answer to the client   
    }) 
    .catch(function(error) { 

     res.status(401).send({error: error}); // in case of any error, we send it back to the client 

    }); 
} 

router.get('/api-function-1', apiFunction1); 
module.exports = router; 

該路由器後,像這樣的輸入:

var api = require('./routes/api'); 
app.use('/api', api); 

因此,您可以看到我向B提出了很多請求,其中包括刷新OAuth2令牌和調用B的API。現在瀏覽器的JavaScript可以調用的API函數,像這樣:

$.ajax('/api/api-function-1' + extra_params, { 
    dataType: 'json', 
    type: 'GET' 
}) 
.done(doSomething) 
.fail(handleError); 

那麼什麼是實現在Django這樣的事情的最好方法?我是Django和python的新手,所以我非常樂於接受任何建議。 Django是否具有與Node的bluebird庫相當的承諾?有關OAuth2部分的任何幫助也非常受歡迎。

+0

我認爲目前你的問題的話來說是要求推薦一個圖書館該怎麼走,但一對夫婦的調整就可以解決的node.js的承諾/事件之間的差異循環和django/wsgi/python請求模型 – dm03514

+0

那麼你會建議哪個名字? –

回答

0

Django符合並通常服務於使用WSGI standard。與節點相比,WSGI和默認的django部署具有完全不同的執行模型。

節點採用event loop。請求進入並放在單個事件循環中。藍鳥(承諾)允許您在事件循環中放置一個事件,並在完成時註冊要執行的操作。 Django沒有事件循環的概念,並沒有與promise/futures(默認情況下)的等價物。在Django中,請求進入並同步執行。有一羣工作人員,當一個工作人員提出請求時,會處理執行代碼直至完成。沒有事件註冊到事件循環中。

Django的代碼如下:

# make an authenticated request using oauth user token 

# if request fails make another request to refresh token 

# remake request