NodeJS后端结合JS连接HTML时页面持续刷新,浏览量异常增长
页面统计功能异常:页面持续刷新导致计数疯涨
问题描述
开发网站访客数与页面浏览量统计功能时,启动后端服务器后页面出现持续自动刷新,页面浏览量计数不断异常增长,同时访客数也存在重复统计的问题。
相关代码
HTML代码
<h2>Page Views: <span id="pageviews-count"></span></h2> <h2>Visits: <span id="visits-count"></span></h2>
页面脚本
const pageviewsCount = document.getElementById('pageviews-count'); const visitsCounts = document.getElementById('visits-count'); if (sessionStorage.getItem('visit') === null) { updateCounter('type=visit-pageview'); } else { updateCounter('type=pageview'); } function updateCounter(type) { fetch('http://localhost:5000/counter?' + type) .then(res => res.json()) .then(data => { pageviewsCount.textContent = data.pageviews; visitsCounts.textContent = data.visits; }) }
计数器控制器(counter.controller.js)
const fs = require('fs'); async function visitCounter(req, res, next) { if (req.url === '/favicon.ico') { res.end(); } const json = fs.readFileSync('./logs/count.json', 'utf-8'); const obj = JSON.parse(json); obj.pageviews = obj.pageviews + 1; if (req.query.type === 'visit-pageview') { obj.visits = obj.visits + 1; } const newJson = JSON.stringify(obj); fs.writeFileSync('./logs/count.json', newJson); res.send(newJson); } module.exports = visitCounter
计数器路由(counter.routes.js)
const express = require('express'); const counter = require('../controllers/counter.controller'); const router = express.Router(); router.route('/') .get(counter); module.exports = router;
计数存储文件(count.json)
{"pageviews":369,"visits":8}
主应用文件(app.js)
const express = require("express"); const cors = require("cors"); const app = express(); const port = 5000; app.use(express.json()); app.use(cors()); app.use('/counter', require('./routes/counter.routes')); app.listen(port, () => { console.log(`http://localhost:${port}`); });
问题分析与修复
核心问题
- 后端未终止/favicon.ico请求:浏览器每次加载页面都会请求/favicon.ico,后端代码中执行
res.end()后没有return,后续计数逻辑仍会运行,导致该请求也会增加浏览量;同时返回的JSON不是浏览器预期的图标资源,引发页面异常刷新。 - 前端未设置会话标记:第一次访问时触发访客计数,但未在sessionStorage中标记会话状态,导致页面刷新后重复触发访客数增长。
修复代码
1. 修正后端控制器
const fs = require('fs'); async function visitCounter(req, res, next) { if (req.url === '/favicon.ico') { res.status(204).end(); // 返回204无内容,告知浏览器无需重试请求 return; // 终止后续代码,避免计数逻辑执行 } const json = fs.readFileSync('./logs/count.json', 'utf-8'); const obj = JSON.parse(json); obj.pageviews = obj.pageviews + 1; if (req.query.type === 'visit-pageview') { obj.visits = obj.visits + 1; } const newJson = JSON.stringify(obj); fs.writeFileSync('./logs/count.json', newJson); res.send(newJson); } module.exports = visitCounter
2. 修正前端脚本
const pageviewsCount = document.getElementById('pageviews-count'); const visitsCounts = document.getElementById('visits-count'); if (sessionStorage.getItem('visit') === null) { updateCounter('type=visit-pageview'); sessionStorage.setItem('visit', '1'); // 标记会话,同一会话内不再重复统计访客 } else { updateCounter('type=pageview'); } function updateCounter(type) { fetch('http://localhost:5000/counter?' + type) .then(res => res.json()) .then(data => { pageviewsCount.textContent = data.pageviews; visitsCounts.textContent = data.visits; }) }
额外优化建议
- 后端改用异步文件读写(
fs.promises.readFile/fs.promises.writeFile),避免同步操作阻塞服务器; - 准备实际的favicon.ico文件,或为该请求返回正确的图标类型响应;
- 高并发场景下,建议用数据库(如Redis、SQLite)替代JSON文件存储计数,防止并发写入导致数据丢失。
内容的提问来源于stack exchange,提问作者Resai
相关产品推荐
相关产品推荐

