【问题标题】:Server sent response but Client not loading the sent content服务器发送响应但客户端未加载发送的内容
【发布时间】:2019-03-04 12:23:06
【问题描述】:

我有简单的节点服务器(nodejs + express + ejs 渲染),当用户尝试加载特定页面时,服务器会发送已编译的 html 并作为响应发送。

为了跟踪用户,我添加了 2 个计数器

一个。当服务器收到对该页面的请求时计数器会增加

b.当客户端加载页面时,它包含一些代码,这些代码会将 HTTP 请求返回到我用作计数器的服务器

现在的问题是,随着时间的推移,sentResponse 计数器和 clientLoad 计数器之间的差异增加了很多,以至于我得到了 sentResponse = 7000clientLoad = 3600

关于可能导致这种行为的任何建议

注意:我还在请求到达我的服务器之前设置了 Cloudfare,我暂停了它,但我仍然得到了巨大的差异?

注意:我还注意到很多用户经常在 4 秒内多次向页面发出请求,但我确信我发送的是有效的 html 并且我不同的是几乎 50%,所以我不认为每个访问的用户页面在 4 秒内按 ctrl+r 2 次或更多次。

代码:

server.js

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

    Tracker.incrementCount('sentResponse');
    res.render(page.ejs, {...});
});

app.get('/client-load-start', (req, res) => {
    Tracker.incrementCount('clientLoadStart');
    res.send(200);
});

page.ejs

<html>
    <head>
        ...
        <script src='/client-load-start?version=<some_random_4_digit_number>'></script>
        ...
    </head>

    <body>
        ...
        ...
    </body>
</html>

【问题讨论】:

  • 我怀疑这是缓存问题。浏览器正在缓存您的页面一段时间。因此,在此期间,如果您请求该页面,它将由缓存提供服务,您的服务器将不会收到任何命中。在浏览器中禁用缓存,然后重试。
  • @MukeshVerma 但如果是这种情况,那么服务器也不会增加 sendResponse 计数吗?因为页面是从浏览器的缓存中加载的,所以服务器不参与任何事情,所以在这种情况下,sendResponse 和 clientLoad 计数器都不会增加,因此它们应该几乎相同,对吧?
  • 请看,如果 b 页面被加载,它将发送 http 请求,这将在您的服务器上增加一个计数器。页面被缓存而不是请求。因此,无论何时加载页面,无论是从缓存还是服务器提供,都会在加载时触发 http 请求,这将导致增量操作。
  • @MukeshVerma Umm 是的,所以在这种情况下,sentResponse 计数器将小于 clientLoaded 计数器,因为服务器没有发送任何响应(由于浏览器缓存),sentResponse 不会增加,但 clientLoaded 会得到无论页面加载的位置如何,都会递增。但在我的情况下,sentResponse 比 clientLoaded 更多
  • 如果您能分享一些代码,我可能会提供帮助。

标签: javascript node.js express browser


【解决方案1】:

对于计数可能不同的原因,我可以想到以下可能性。

  • 设置缓存标头 (Cache-Control) 可能会导致浏览器缓存请求。
  • JS 未在客户端浏览器中启用,因此无法对服务器进行 AJAX 调用以更新 clientLoad 计数器(这不太可能,但仍然是其中一种可能性)。
  • 人们甚至在页面加载之前就与页面进行了交互,导致 AJAX 调用无法触发。人们在页面加载之前重新加载了页面。

如果您只是想跟踪

【讨论】:

  • 1.已经到位,我正在为那个 2 使用无缓存 npm 包。是的,我同意这也不太可能,即使在这种情况下,sendResponse 计数不会比 clientLoad 3 多大约 50%。不知道为什么如果用户与页面交互会导致不运行 ajax 代码,是的,事实上人们经常重新加载页面(阅读我的问题中的 Note#2)
  • 3.这取决于何时请求 ajax 调用。例如,如果仅在整个页面加载后触发 ajax 调用,并且用户在整个页面加载之前与页面交互(单击页面中的某个链接并导航离开)。
  • 关于您的注释 2,您是否处于多集群环境中,多个线程可以运行相同的代码。如果是这样,您可能会遇到计数器变量的同步问题,从而导致数字差异很大。就像我说的,有更简单的方法来做你想做的事。我不会太担心通过跟踪发送和接收的请求计数器来确保响应实际传递给最终客户端。 Node.JS 和 N/W 将确保响应到达用户。您能否也谈谈这些计数器的用途。
  • @NIHANTDESAI 你能分享客户端加载启动脚本吗?
  • 所以我使用 2 种技术来触发客户端加载启动事件,1. 在 部分 2. 像素标记,两者几乎相同,数据库中这两个计数器之间的值差异可以忽略不计
【解决方案2】:

您可以尝试使用缓存清除方法。每次浏览器加载/dashboard 时,浏览器都会为您的/client-load-start 路由获取脚本源。问题是/client-load-start 被请求的唯一时间是浏览器的缓存被清除时,或者网站第一次加载时。这将导致两个计数随时间变化很大的问题。

尽量让浏览器认为/client-load-start是一个需要下载的新脚本。您可以通过向 src 添加查询参数来完成此操作。

<script src='/client-load-start?<%- Date.now()%>=1'></script>

每次浏览器访问/dashboard 时,它都会尝试下载新脚本,因为查询参数已更改,从而破坏了缓存。

【讨论】:

  • 我已经准备好了,所以在将 EJS 模板编译为 HTML 时,我生成了一个随机数,并将其附加到 /client-load-start?version= 然后我正在将最终的 HTML 发送给客户端,很抱歉在我的问题中没有提及它,我会立即更新它
  • 尝试完全更改文件名app.get('/client-load-start/:random',然后在 EJS 中/client-load-start/&lt;%= randomValue %&gt;。这完全改变了路径,并将破坏任何持久性。
【解决方案3】:

事件顺序

  1. 浏览器请求/dashboard
  2. 服务器增加sentResponse,渲染page.ejs并发送给浏览器
  3. 浏览器接收到page.ejs并检测到&lt;script&gt;标签
  4. 浏览器检查脚本 URL 是否在浏览器缓存中
    • 如果在缓存中找到脚本 URL,则序列到此结束; clientLoad 保持不变
  5. 浏览器从您的服务器请求脚本
  6. 服务器执行get请求,增加clientLoad

问题

这里的“问题”是浏览器——或者浏览器和你的服务器之间的任何代理——会缓存返回的脚本,除非你另有指示。

请注意,在大多数情况下,缓存实际上是预期和预期的行为。这也是浏览器的默认行为。

解决方案

要指示浏览器(或代理)避免缓存文件,您可以设置cache control headers

app.get('/client-load-start', (req, res) => {
    Tracker.incrementCount('clientLoadStart');
    res
       .set('cache-control', 'max-age=0; private; no-cache')
       .send(200);
});

这将指示浏览器从不缓存请求并始终获取新副本,因此每次请求都会增加clientLoadStart

另一种方式是“cache busting”,这意味着您有意更改脚本的 URL,例如通过像上面那样附加一个随机数,从而“破坏”缓存键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    • 2018-06-20
    相关资源
    最近更新 更多