【问题标题】:How to make Node.js handle multiple requests efficiently?如何让 Node.js 高效地处理多个请求?
【发布时间】:2018-02-06 00:45:02
【问题描述】:

我正在尝试编写一个 Node.js 应用程序,它接受来自客户端的传入请求,然后调用远程服务器上的某些 Web 服务以检索数据。

const express = require('express')
const request = require('request')
const moment = require('moment')

const app = express()

app.get('/', (req, res) => {

    request('http://localhost/sleep.php', (error, response, body) => {
        res.send('get data at ' + moment().format())
    })

})

app.listen(3000)

远程服务是用PHP编写的:

<?php

    sleep(10);
    echo 'Return something!';

问题是,如果有新请求进来,那么 Node.js 会被阻塞,直到它完成最后一个回调。如何解决这个问题?有什么想法吗?

更新:

我实际上通过 Firefox 同时发出了两个请求,第二个请求花费了将近 20 秒。

Please see the image here

【问题讨论】:

  • 谷歌搜索“nodejs async await”产生了这个结果:blog.risingstack.com/mastering-async-await-in-nodejs
  • @AlexanderTaran 我看不出这与 async/await 有什么关系...
  • 我没有看到在这个例子中节点是如何被阻止的,你没有做同步请求。每个请求大约需要 10 秒,但您现在可以处理多个并发请求,除非您没有显示完整的代码。
  • 更重要的是:这绝对不是 PHP 问题,也很可能不是 Node.js 问题。这是浏览器和 HTTP 的问题。

标签: php node.js firefox


【解决方案1】:

这里有一个快速演示,浏览器不会对同一 URL 的并发请求进行管道处理,但不同的 URL 通常会。向查询字符串添加不同的值是一种解决此问题的技术:例如,localhost:3000/?1517849200341 使用 Date.now()。

(广义上讲,流水线在 HTTP/1.1 中被禁用,但浏览器会使用多个 TCP 连接到同一端。流水线是 HTTP/2 的一部分,通过设置最大流数。我真的不知道这是什么表示或如何解释下面的结果。)

async function log(fn) {
  console.log(Date());
  await Promise.all(fn());
  console.log(Date());
}

const req1 = 'https://httpbin.org/delay/1';
const req2 = 'https://nghttp2.org/httpbin/delay/1';

const req3 = 'https://httpbin.org/delay/1?a';
const req4 = 'https://httpbin.org/delay/1?b';
const req5 = 'https://httpbin.org/delay/1?c';
const req6 = 'https://httpbin.org/delay/1?d';

const req7 = 'https://nghttp2.org/httpbin/delay/1?a';
const req8 = 'https://nghttp2.org/httpbin/delay/1?b';
const req9 = 'https://nghttp2.org/httpbin/delay/1?c';
const req10 = 'https://nghttp2.org/httpbin/delay/1?d';

btn1.addEventListener('click', () => log(() => [
  fetch(req1),
  fetch(req1),
  fetch(req1),
  fetch(req1),
  fetch(req1),
]));

btn2.addEventListener('click', () => log(() => [
  fetch(req2),
  fetch(req2),
  fetch(req2),
  fetch(req2),
  fetch(req2),
]));

btn3.addEventListener('click', () => log(() => [
  fetch(req1),
  fetch(req3),
  fetch(req4),
  fetch(req5),
  fetch(req6),
]));

btn4.addEventListener('click', () => log(() => [
  fetch(req2),
  fetch(req7),
  fetch(req8),
  fetch(req9),
  fetch(req10),
]));
<button id=btn1>HTTP/1.1, same URLs</button>
<button id=btn2>HTTP/2, same URLs</button>
<button id=btn3>HTTP/1.1, different URLs</button>
<button id=btn4>HTTP/2, different URLs</button>

【讨论】:

    【解决方案2】:

    Chrome 缓存是罪魁祸首。在每个选项卡中打开一个 chrome 开发控制台并单击“禁用缓存”然后刷新每个选项卡,您会看到异步返回的响应。我假设 Firefox 可能在某处也有缓存设置。 或者使用 Postman 发出多个请求...

    或者,如果您真的想在多个选项卡中看到此功能,我想您也可以禁用节点服务器的缓存(除了概念证明之外,我不推荐使用它):

    ...
    var nocache = require('nocache')
    const app = express()
    app.use(nocache())
    ...
    

    【讨论】:

    • 不过,从客户端禁用缓存并不是一个现实的解决方案。
    • @JoshLee 你是什么意思?这不是一个解决方案,它是一种证明 express 实际上是异步服务的方法,但 chrome 实际上并没有异步发出 http 请求。贴出来的代码没有问题,问题是浏览器缓存。
    • 这是一个公平的观点:目标实际上并不是在两个浏览器窗口中加载相同的 URL;这只是一种查看 Node.js 是否真的可以处理这个问题的技术。
    • 我认为这与浏览器缓存无关,因为即使我从隐身窗口拨打电话也无法正常工作。
    • 我也测试了库nocache,但结果相同。
    猜你喜欢
    • 1970-01-01
    • 2022-01-21
    • 2016-12-10
    • 1970-01-01
    • 2013-06-12
    • 2018-08-19
    • 2013-01-12
    • 2013-01-31
    • 2021-05-25
    相关资源
    最近更新 更多