2014-11-22 60 views
1

最近我開始學習一些關於Node.js及其功能的知識,並嘗試將它用於某些Web服務。 我想創建一個Web服務,它將作爲Web請求的代理。 我希望我的服務,工作方式:Node.js以異步數據響應

  1. 用戶要訪問我的服務 - >http://myproxyservice.com/api/getuserinfo/tom
  2. 我的服務將執行請求 - >http://targetsite.com/user?name=tom
  3. 回覆了數據會得到反映給用戶。

要實現它,我用下面的代碼:

app.js:

var express = require('express'); 
var bodyParser = require('body-parser'); 
var app = express(); 

app.use(bodyParser.urlencoded({ extended: false })); 
app.use(bodyParser.json()); 

var proxy = require('./proxy_query.js') 

function makeProxyApiRequest(name) { 
    return proxy.getUserData(name, parseProxyApiRequest); 
} 

function parseProxyApiRequest(data) { 
    returned_data = JSON.parse(data); 
    if (returned_data.error) { 
    console.log('An eror has occoured. details: ' + JSON.stringify(returned_data)); 
    returned_data = ''; 
    } 
    return JSON.stringify(returned_data); 
} 

app.post('/api/getuserinfo/tom', function(request, response) { 
    makeProxyApiRequest('tom', response); 
    //response.end(result); 
}); 

var port = 7331; 

proxy_query.js:

var https = require('https'); 

var callback = undefined; 

var options = { 
    host: 'targetsite.com', 
    port: 443, 
    method: 'GET', 
}; 

function resultHandlerCallback(result) { 
    var buffer = ''; 

    result.setEncoding('utf8'); 
    result.on('data', function(chunk){ 
     buffer += chunk; 
    }); 

    result.on('end', function(){ 
     if (callback) { 
      callback(buffer); 
     } 
    }); 
} 

exports.getUserData = function(name, user_callback) { 
    callback = user_callback 
    options['path'] = user + '?name=' + name; 

    var request = https.get(options, resultHandlerCallback); 

    request.on('error', function(e){ 
     console.log('error from proxy_query:getUserData: ' + e.message) 
    }); 

    request.end(); 
} 
app.listen(port); 

我希望我沒有擰驗證碼因爲我替換了一些東西來適合我的例子。

無論如何,問題是我想在HTTP請求完成後發送響應給用戶,我不能找到如何做,因爲我使用express和express使用異步調用,所以請求http。 我知道如果我想這樣做,我應該傳遞makeProxyApiRequest響應對象,以便能夠將它傳遞給回調函數,但由於asyn問題而不可行。

有什麼建議嗎? 幫助將不勝感激。

+0

我注意到'makeProxyApiRequest'和'parseProxyApiRequest'函數都被阻塞。對於這兩種情況,我強烈推薦以下Node的'function name(input,callbackfunction)'模式,當一切正常時,或者回調函數稱爲'callback(false,result)' (someerrorobjectorstring)'當出現問題時。 – 2014-11-22 20:37:32

+0

謝謝,這是一個好主意。但它不能解決問題。你有什麼建議嗎? – CodeNinja 2014-11-22 20:41:18

+0

給你寫了一個答案,但要記住的一件事是,用戶的請求在他們的瀏覽器和他們聯繫的服務器之間總是*異步,所以這實際上不是問題。表達強迫你異步形成你的反應的事實在這裏實際上是一種好處,所以你不會試圖同步做所有事情。 – 2014-11-22 20:46:20

回答

2

由於您使用的函數來處理你的路線處理內部請求,最好是寫他們的快遞中間件功能,所採取的具體請求/響應對,並利用快遞的next級聯模式:

function makeProxyApiRequest(req, res, next) { 
    var name = parseProxyApiRequest(req.name); 
    res.locals.userdata = proxy.getUserData(name); 
    next(); 
} 

function parseProxyApiRequest(req, res, next) { 
    try { 
    // remember that JSON.parse will throw if it fails! 
    data = JSON.parse(res.locals.userdata); 
    if (data .error) { 
     next('An eror has occoured. details: ' + JSON.stringify(data)); 
    } 
    res.locals.proxyData = data; 
    next(); 
    } 
    catch (e) { next("could not parse user data JSON."); } 
} 

app.post('/api/getuserinfo/tom', 
    makeProxyApiRequest, 
    parseProxyApiRequest, 
    function(req, res) { 
    // res.write or res.json or res.render or 
    // something, with this specific request's 
    // data that we stored in res.locals.proxyData 
    } 
); 

更妙的是現在搬完中間件功能集成到自己的文件,所以你可以簡單地做:

var middleware = require("./lib/proxy_middleware"); 
app.post('/api/getuserinfo/tom', 
    middleware.makeProxyApiRequest, 
    middleware.parseProxyApiRequest, 
    function(req, res) { 
    // res.write or res.json or res.render or 
    // something, with this specific request's 
    // data that we stored in res.locals.proxyData 
    } 
); 

,並保持你app.js儘可能小。請注意,客戶端的瀏覽器將簡單地等待快速響應,發生一次使用res.write,res.jsonres.render等。在此之前,連接只是在瀏覽器和服務器之間保持打開狀態,所以如果你的中間件調用需要很長時間,那很好 - 瀏覽器會很高興地等待一個響應被髮送回去,並且會做其他事情在同一時間。現在

,爲了獲得name,我們可以使用快速的參數結構:

app.param("name", function(req, res, next, value) { 
    req.params.name = value; 
    // do something if we need to here, like verify it's a legal name, etc. 
    // for instance: 
    var isvalidname = validator.checkValidName(name); 
    if(!isvalidname) { return next("Username not valid"); } 
    next(); 
}); 

... 

app.post("/api/getuserinfo/:name", ..., ..., ...); 

使用這個系統,任何途徑的:name部分將基於我們使用的應用程序定義的name參數進行處理。 PARAM。請注意,我們並不需要定義其再次:我們可以做以下的,它會都只是工作:

app.post("/api/getuserinfo/:name", ..., ..., ...); 
app.post("/register/:name", ..., ..., ...); 
app.get("/api/account/:name", ..., ..., ...); 

和每路線:名稱,對於「名稱」參數的代碼。處理程序將在踢

對於proxy_query.js文件,重寫這一個適當的模塊可能比使用單獨的出口更安全:

// let's not do more work than we need: http://npmjs.org/package/request 
// is way easier than rolling our own URL fetcher. In Node.js the idea is 
// to write as little as possible, relying on npmjs.org to find you all 
// the components that you need to glue together. If you're writing more 
// than just the glue, you're *probably* doing more than you need to. 
var request = require("request"); 
module.exports = { 
    getURL: function(name, url, callback) { 
    request.get(url, function(err, result) { 
    if(err) return callback(err); 
    // do whatever processing you need to do to result: 
    var processedResult = .... 
    callback(false, processedResult); 
    }); 
    } 
}; 

,然後我們可以使用它作爲中間件proxy = require("./lib/proxy_query");我們需要實際上做URL數據提取。

+0

很好的答案,非常感謝你!似乎它解決了我的問題。現在就去實施它。您的幫助非常感謝! – CodeNinja 2014-11-22 21:08:26

+0

嗨邁克,我試着實現你上面說的。我得到了一般的概念,但我無法弄清楚的東西很少。你在makeProxyApiRequest中寫道:var name = parseProxyApiRequest(req.name);這個req.name來自哪裏?誰提供它?對於另一個問題,通過做proxy.getUserData(name);你的意思是proxy.getURL?如果是的話,你在哪裏提供回調,以及如果你的結果是異步的,你可以把結果賦給一個變量?你有問題嗎? – CodeNinja 2014-11-22 22:50:23

+0

讓我把這個部分加入到答案中,導致我們如何得到那真的很酷。 – 2014-11-23 01:50:24