Node Express JS - 处理同时发送的POST请求到服务器

3
我有一个使用Express处理GET/POST请求的节点项目,我已经创建了不同种类请求的路由。其中一个路由是 /api/twitter/search,基本上调用一个使用promise获取Twitter feeds的函数,并使用response.write将数据作为响应发送。
现在的情况是,当我对相同输入数据进行两个同时的请求时,运行中的代码会重叠,导致响应不一致。我希望服务器能够独立地处理任意数量的请求,即使请求的操作包含多个异步调用/承诺。
请问有人可以帮帮我吗?我完全是js开发的新手,所以任何帮助都将不胜感激。
以下是代码:
我创建的路由如下:
app.post('/api/twitter/fetch',function(req,res){
        var hashTag = req.body.hashtag;
        var userVals = {
            userEmail: req.body.uemail,
            tokenVal: req.body.utoken
        }
        tokenController.validateToken(userVals,function(error,data){
            returnObject = {status:true, data:'', error:''};
            if(error!=''){
                returnObject.status = false;
                returnObject.data = data;
                returnObject.error = error;
                res.send(returnObject);       
            }else{
                var twitterController = require('../controllers/testTwitterController');
                twitterController.fetchTweets(res,hashTag);
            }
        });
    });

以下是fetchTweets函数的代码:
var Twitter = require('twitter');
var params = require('../config/params.js');
var moment = require('moment');
//var promise = require('promise');
var globalHashTag = ''; var tweetArr = []; var  responseHandle = [];
client = new Twitter({
    consumer_key: params.consumer_key,
    consumer_secret: params.consumer_secret,
    access_token_key: params.access_token_key,
    access_token_secret: params.access_token_secret

});
function fetchTweetsAsync(hashTag,max_id){
    var days = 7; //Days you want to subtract from today
    var tillDate = (new Date()).toISOString().split('T')[0];
    var sinceDate = (new Date((new Date).getTime() - ((days) * 24 * 60 * 60 * 1000))).toISOString().split('T')[0];
    var param = {q:'#'+hashTag+' since:'+sinceDate+' until:'+tillDate,include_entities:true,result_type:'recent',count:100};
    if(max_id !== '' || typeof max_id != undefined)
        param.max_id = max_id;
    return new Promise(function(resolve,reject){
        // do a thing, possibly async, then..
        client.get('search/tweets',param,function(error,tweets,response){
            if(error){
                console.log(error);
                process.exit(1);
            }
            if(tweets.statuses.length){//If we get tweets, send them via promise
                //console.log("\n\n\n\n--------------------------------------------------------- Tweets fetched for #"+hashTag+ "-------------------------------------------------------------\n\n\n");
                resolve(tweets.statuses,hashTag);
            }
        });
    });
};


function getMaxHistory(tweets,hash){
    //console.log("\n\n~~~~~~~~~~~~~~~~Total: "+ tweets.length + " results found!~~~~~~~~~~~~~~~~\n\n");
    tweets.map((tweet)=>{
        process.stdout.write('.');
        created_at = moment(tweet.created_at).format("YYYY-MM-DD");
        tweetArr.push(created_at);
    });
    max_id = tweets[tweets.length - 1].id - 1;
    if(tweets.length == 100){
        process.stdout.write('*');
        return fetchTweetsAsync(hash,max_id).then(getMaxHistory);
    }
    else{
        var total = tweetArr.length;
        var finalArr = []; 
        finalArr = getDateWiseCount(tweetArr);
        tweetArr = [];
        console.log("Count array generated!");
        console.log("Total: "+total);
        finalArr = JSON.stringify({status:true,total:total,counts:finalArr});
        return finalArr;
        // console.log(finalArr);
        //responseHandle.send([{status:true,total:total,counts:finalArr}]);
    }
}

function getDateWiseCount(tweetArr){
    tweetArr = tweetArr.sort(); //We have a sorted array, need to get the counts now


    var current = null;
    var count = 0; returnarr = [];

    for(var i = 0; i < tweetArr.length; i++)
    {
        if(tweetArr[i] != current)
      {
        if(count > 0)
        {
            var date = new Date(current).toISOString();
            var val = count;
            returnarr.push({date:date,value:val});
            //console.log(returnarr);
            //console.log(current + " " + count + "<br/>");

        }
        current = tweetArr[i];
        count = 1;
      }
      else
      {
        count++;
      }
    }

    if(count > 0){
        var date = new Date(current).toISOString();
        var val = count;
        returnarr.push({date:date,value:val});
    }
    return returnarr;
}

module.exports = {
    fetchTweets: function(res,hashTag){
        responseHandle = res;
        fetchTweetsAsync(hashTag).then(getMaxHistory).then(function(finalArr){
            res.write(finalArr);
            res.end();
        });
    }
};

我认为你的解释有误,“我同时向同一路由发送两个请求,使用相同的输入数据,然后这两个请求的结果竟然一致”,你到底是什么意思?在相同的GET和输入数据上给出相同的结果定义了一致性,你想表达什么? - Dinca Adrian
抱歉我没有表达清楚。我的意思是,我在Postman上使用URL:localhost:8080/api/twitter/fetch并提供一些输入数据。这个路由链接到一个方法,该方法使用输入数据返回一些输出,使用res.write。当我同时在两个Postman标签页中打开相同的URL时,服务器没有将其视为两个不同的请求,而是在第二个实例中使用第一个请求体,并反之亦然。 - Kushagra
3
听起来你没有正确声明变量,所以它们被“提升”为全局变量。当然,我们只能猜测,因为你没有贴出任何代码。 - robertklep
现在我明白了,但你能发布一下带有“get”的路由器部分,或阅读此内容并尝试将其应用于您的代码吗?https://dev59.com/DWIj5IYBdhLWcg3w04Qo 。 - Dinca Adrian
@robertklep 谢谢你的回答,对我很有帮助。很抱歉我在发问题时没有提供相关代码,因当时无法获取。问题似乎出在变量作用域声明上。如果你愿意,可以单独发布回答,我会为它投票支持。谢谢! - Kushagra
1个回答

4
处理并发请求时出现意外行为,特别是其中一个请求似乎会“影响”另一个请求时,几乎总是由于变量没有正确声明(使用varletconst)引起的。这可能导致这些变量成为全局变量,意味着它们在所有请求之间共享,这可能会导致各种问题。如果可能,在编辑器中添加linter支持可以帮助捕获这些情况。对于Vim,常用的插件是syntastic,它可以使用eslint来语法检查JS代码。几乎所有常见的编辑器都有相应的插件。

我仍然面临这个问题。谢天谢地,我现在可以访问代码了,我将很快编辑问题并发布答案。我相当确定声明可能是问题所在,但不知道如何在给定的代码中处理它。请帮忙! - Kushagra
错误声明或未声明的变量:returnObjectcreated_atmax_idreturn_arrtweetArr - robertklep
请问你能否在你的端上尝试运行这段代码?即使使用var在本地定义,我也无法找到解决方法。请注意,在设置时,请从路由代码中删除令牌验证部分。 - Kushagra
如果您需要API密钥等,请告诉我。 - Kushagra
@robertklep 我一直很担心这个。谢谢! - Rashomon
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接