Chrome长时间运行出现net::ERR_HTTP2_PROTOCOL_ERROR及Ajax定时请求中断问题
问题分析与解决方案
问题现象
- 页面循环播放短视频数小时,每60秒通过Ajax请求记录观看时长,运行数小时、数百次请求后随机出现错误:
- Chrome:
Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR(无指向对象) - Opera:
GET '视频托管文件长URL' NET::ERR_CONNECTION_RESET 200 - Chrome:指向Ajax JS文件的
net::ERR_HTTP2_PROTOCOL_ERROR
- Chrome:
- 仅记录时长的Ajax请求中断,其他间隔≥60秒的日志请求及视频播放均正常。
可能原因排查
- HTTP/2连接复用限制
浏览器会复用HTTP/2长连接发送请求,部分服务器、CDN或路由器对长连接的复用次数、闲置时长有阈值,超过后会强制断开连接。其他请求因路径/参数差异使用了不同连接池,未受影响。 - DDoS防护误拦截
持续数小时的固定模式请求(相同路径、相似参数)可能被托管商的WAF/DDoS防护误判为自动化攻击,触发临时拦截。 - 前端请求逻辑缺陷
当前代码仅在请求成功后才触发下一次请求,若单次请求失败可能导致连接资源未正常释放,积累后引发异常。 - 服务器资源泄漏
后端MySQL连接、进程资源未正确释放,长时间运行后部分请求无法处理,但其他请求正常的话该可能性较低。
修复与优化建议
前端代码优化
添加失败重试机制与随机延迟,避免固定请求模式,防止单次失败中断流程:
// 更新日志时长 function updateVidTime() { const url = current_url; $.ajax({ url: url, type: 'POST', data: { 'updateTime': 1, 'videoID': videoID, 'visitID': visitID, 'current_url': current_url, 'timeSec': timeSec, }, success: function(data) { const response = JSON.parse(data); timeSec = parseInt(response.timeSec) + waitTime; timerStarted = 0; // 添加1-3秒随机延迟,避免固定请求间隔 const randomDelay = Math.floor(Math.random() * 3000); runVidTimer(timeSecMS + randomDelay); }, error: function(xhr, status, error) { // 请求失败最多重试3次 if (typeof this.retryCount === 'undefined') this.retryCount = 0; if (this.retryCount < 3) { this.retryCount++; setTimeout(() => updateVidTime(), 2000); } else { // 多次失败后重启定时器,避免流程中断 runVidTimer(timeSecMS); } } }); } function runVidTimer(delay = timeSecMS) { timerSetTmOut = setTimeout(updateVidTime, delay); }
后端代码优化
修复SQL注入风险,确保资源正确释放:
if (isset($_POST['updateTime'])) { $videoID = $_POST['videoID']; $visitID = $_POST['visitID']; $current_url = $_POST['current_url']; $timeSec = $_POST['timeSec']; // 使用预处理语句防止SQL注入 $sql = "UPDATE log SET timeSec = ? WHERE visitID = ? AND page = ?"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "sss", $timeSec, $visitID, $current_url); $result = mysqli_stmt_execute($stmt); if ($result) { $response = [ 'timeSec' => $timeSec ]; echo json_encode($response); mysqli_stmt_close($stmt); exit(); } // 处理执行失败场景 echo json_encode(['error' => 'Update failed']); exit(); }
额外排查动作
- 切换HTTP/1.1测试:前端Ajax添加
xhrFields: {withCredentials: false},或服务器临时禁用HTTP/2,验证是否为HTTP/2协议层面问题。 - 核查托管商防护日志:联系托管商确认该请求是否被WAF拦截,提供请求模式说明申请调整规则。
- 更换网络环境测试:排除家用路由器、ISP的长连接超时限制问题。
内容的提问来源于stack exchange,提问作者brian dm
相关产品推荐
相关产品推荐

