【问题标题】:Express request is called twice快速请求被调用两次
【发布时间】:2012-10-20 11:00:21
【问题描述】:

为了学习 node.js,我正在创建一个小应用程序,它获取一些存储在 mongoDB 中的 rss 提要,处理它们并从这些提要中创建一个提要(按日期排序)。

它会解析约 50 个 rss 提要的列表,其中包含约 1000 个博客项目,因此解析整个内容的时间很长,因此我输入了以下 req.connection.setTimeout(60*1000); 以获得足够长的时间来获取和解析所有提要.

一切运行良好,但请求被调用了两次。 (我用wireshark查过,我不认为这与favicon有关)。

我真的不明白。

您可以在这里测试自己:http://mighty-springs-9162.herokuapp.com/feed/mde/20(它应该创建一个包含最近 20 篇关于“mde”的文章的 rss 提要)。

代码在这里:https://github.com/xseignard/rss-unify

如果我们专注于有趣的部分:

我有一个这样定义的路线:app.get('/feed/:name/:size?', topics.getFeed);

topics.getFeed 是这样的:

function getFeed(req, res) {
  // 1 minute timeout to get enough time for the request to be processed
  req.connection.setTimeout(60*1000);   

  var name = req.params.name;
  var callback = function(err, topic) {
  // if the topic has been found
  if (topic) {
    // aggregate the corresponding feeds
    rssAggregator.aggregate(topic, function(err, rssFeed) {
      if (err) {
        res.status(500).send({error: 'Error while creating feed'});
      }
      else {
        res.send(rssFeed);
      }
    },
    req);
  }
  else {
    res.status(404).send({error: 'Topic not found'});
  }};
  // look for the topic in the db
  findTopicByName(name, callback);
}

所以没什么特别的,但是这个 getFeed 函数还是被调用了两次。

那里有什么问题?有什么想法吗?

【问题讨论】:

  • 最常见的问题是你忘记使用return
  • 您好 mvbl-fst,我不明白您忘记return 的意思。你能解释更多吗?
  • 我可能对上述内容有误,在这段代码中,没有什么能让它执行两次(favicon.ico 除外,但你说这是不可能的)。我唯一要做的就是做return findTopicByName(name, callback);。但很确定它不会有帮助。
  • 你能把它添加到 git 中,这样我就可以拉出来看看发生了什么?
  • 所以我做了更多的调查,它似乎只发生在 Chromium(和我认为是 Chrome)上,而在 firefox 上不会发生。

标签: node.js http express


【解决方案1】:

这让我很生气。很可能是 Firebug 扩展在后台发送每个 GET 请求的副本。尝试关闭 Firebug 以确保不是问题所在。

【讨论】:

  • 这也是我的问题。对localhost:3000/tracks 的GET 请求被调用了一次,对localhost:3000/tracks/post 的GET 请求被调用了两次。当我关闭 Firebug(在 Chrome 中)时,第二个请求也被调用了一次。
  • 这也发生在我身上,但使用的是 chrome 开发工具。我正在拔头发试图找出原因。
  • 我也有同样的问题,绝对不是萤火虫。在我的情况下,它与请求响应时间有关,因为我的请求被调用两次执行大量计算并在 3-4 分钟后发送响应。如果我只是快速响应而不涉及计算,那么第二个请求就不会发生。
  • 我还要注意我的请求不是 GET 请求,而是被调用了两次的 POST 请求。
  • @user619271 在您的情况下是超时问题。 Nodejs 默认有 2 分钟。您可以对其进行一般调整或根据要求进行调整。
【解决方案2】:

我在本地机器上使用Google Cloud Functions Framework(使用express 处理请求)时遇到了同样的问题。每个fetch 请求(在浏览器控制台和网页中)都会导致对服务器的两个请求。该问题与 CORS 有关(因为我使用了不同的端口),Chrome 在实际调用之前进行了 OPTIONS 方法调用。由于我的代码中不需要 OPTIONS 方法,因此我使用 if 语句返回空响应。

if(req.method == "OPTIONS"){
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.status(204).send('');
}

花了将近 3 小时敲打我的头。感谢 user105279 给出的提示。

【讨论】:

  • 伟大的收获! - 我也在敲我的头,因为直到我部署到不同的域才出现这种情况。 (另外,我必须在 if 块中添加“return;”)
【解决方案3】:

如果您的网站上有网站图标,请将其删除并重试。如果您的问题得到解决,请重构您的网站图标 url

【讨论】:

  • 这很棒。我已经向 js 文件发出了两次请求。我的 js 文件根 url 结构和快速路由 url 结构是相同的。这提出了两个要求。只是因为这个答案我才感觉到
【解决方案4】:

我现在或多或少地在做同样的事情,并注意到同样的事情。

我正在通过在 chrome 中输入 api 地址来测试我的服务器,如下所示:

http://127.0.0.1:1337/links/1

然后,我的 Node.js 服务器会根据 id 使用 json 对象进行响应。

我在 get 方法中设置了一个控制台日志,并注意到当我在 chrome 的地址栏中更改 id 时,它会发送一个请求(在按 Enter 实际发送请求之前),并且在我实际发送请求之后服务器接受另一个请求点击进入。无论是否打开 chrome 开发控制台,都会发生这种情况。

IE 11 的工作方式似乎不同,但我现在没有安装 Firefox。

希望对某人有所帮助,即使这是一种旧线程:)

/J

【讨论】:

  • 从 Firefox 尝试时,它会被触发两次。但是,当我尝试使用 POSTMAN 发送请求时,它只触发了一次。因此我可以确认,这个问题源于浏览器的工作方式。
【解决方案5】:

我要修复listen.setTimeoutaxios.defaults.timeout = 36000000

节点js

var timeout = require('connect-timeout'); //express v4

//in cors putting options response code for 200 and pre flight to false
app.use(cors({ preflightContinue: false, optionsSuccessStatus: 200 }));

//to put this middleaware in final of middleawares
app.use(timeout(36000000)); //10min
app.use((req, res, next) => {
   if (!req.timedout) next();
});


var listen = app.listen(3333, () => console.log('running'));
listen.setTimeout(36000000); //10min

反应

import axios from 'axios';

axios.defaults.timeout = 36000000;//10min

经过 2 天的尝试

【讨论】:

    【解决方案6】:

    您可能不得不进一步增加超时时间。我还没有看到快速来源,但它只是在超时时发出声音,它会重试。

    【讨论】:

      【解决方案7】:

      确保你给 res.send(); axios 调用需要来自服务器的值,因此会在 120 秒后发回调用请求。

      【讨论】:

        【解决方案8】:

        我在使用 Express 4 时遇到了同样的问题。我认为这与它如何解析请求参数有关。解决方案是确保您的params 得到解决,例如在if 块中检查它们:

        app.get('/:conversation', (req, res) => {
            let url = req.params.conversation;
        
            //Only handle request when params have resolved
            if (url) {
                res.redirect(301, 'http://'+ url + '.com')
            }
        })
        

        【讨论】:

          【解决方案9】:

          就我而言,我的 Axios POST 请求被 Express 接收了两次,第一个没有正文,第二个带有正确的有效负载。从 Postman 发送的相同请求仅正确接收一次。事实证明,Express 是在不同的端口上运行的,所以我的请求是跨源的。这导致 Chrome 向同一个 url(POST url)发送了一个预检 OPTION 方法请求,而我在 Express 中的 app.all 路由也处理了那个。

          app.all('/api/:cmd', require('./api.js'));
          

          将 POST 与 OPTIONS 分开解决了这个问题:

          app.post('/api/:cmd', require('./api.js'));
          app.options('/', (req, res) => res.send());
          

          【讨论】:

            【解决方案10】:

            我遇到了同样的问题。然后我尝试添加return,它没有工作。但是当我添加 return res.redirect('/path'); 时它会起作用

            【讨论】:

              【解决方案11】:

              我遇到了同样的问题。然后我打开 Chrome 开发工具,发现 favicon.ico 是从我的 Express.js 应用程序中请求的。我需要修复注册中间件的方式。

              Screenshot of Chrome dev tools

              【讨论】:

                【解决方案12】:

                我也有双重要求。在我的情况下,它是从 http 到 https 协议的转发。您可以通过比较来检查是否是这种情况

                req.headers['x-forwarded-proto']
                

                它将是“http”或“https”。 我可以通过调整中间件触发的顺序来解决我的问题。

                【讨论】:

                  猜你喜欢
                  • 2021-10-22
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-08-13
                  • 2017-12-19
                  • 1970-01-01
                  • 2016-10-20
                  • 1970-01-01
                  相关资源
                  最近更新 更多