React集成TradingView图表重复调用API致本地服务崩溃问题
React + TradingView 应用重复请求打崩本地服务问题排查
问题背景
- 个人练习开发的简易React应用,会向本地8000端口服务发起API请求获取数据,渲染至TradingView图表。
- 修改服务端部分取值触发请求后,应用会重复发起约35次请求直到本地服务器崩溃,前端抛出
net::ERR_CONNECTION_REFUSED错误,数据无法正常展示。 - 项目代码分为两部分:第一部分用于获取名称类示例数据,运行无异常;第二部分用于获取图表所需的K线数据,是问题触发模块,对应实现代码如下:
getBars: async ( symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback ) => { try { if (resolution === '1D') { resolution = 1440; } const response2 = await axios.get('http://localhost:8000/chart'); console.log('got bars data'); const bars = response2.data.map((el) => ({ time: new Date(el.timeInterval.minute).getTime(), // date string in api response low: el.low, high: el.high, open: Number(el.open), close: Number(el.close), volume: el.volume, })); if (bars.length) { onHistoryCallback(bars, { noData: false }); } else { onHistoryCallback(bars, { noData: true }); } console.log('bars done'); } catch (err) { console.log({ err }); } };
异常表现
- 问题触发时,控制台会重复打印
got bars data与bars done日志,直到本地服务崩溃后抛出连接错误,数据无法正常渲染。 - 补充观察:使用可正常运行的数据集时,控制台不会打印上述两个日志,但图表仍可正常展示数据。
问题相关数据集
触发异常的数据集
{"timeInterval":{"minute":"2022-03-14T23:45:00Z"},"volume":0.05,"high":3.910209183178435e-9,"low":3.910209183178435e-9,"open":"3.910209183178435e-09","close":"3.910209183178435e-09"}
可正常运行的数据集
{"timeInterval":{"minute":"2022-03-17T15:00:00Z"},"volume":0.05,"high":0.00001255389794727055,"low":0.00001255389794727055,"open":"1.255389794727055e-05","close":"1.255389794727055e-05"}
问题根因
重复请求的核心原因是返回给TradingView的K线数据不符合规范,库判定未拿到有效历史数据,自动触发重试逻辑,直到达到内置重试上限(约35次),大量请求直接打崩本地服务,具体不符合规范的点有四个:
- 完全忽略
periodParams传入的from、to时间范围参数,每次请求全量返回所有数据,也没有对返回的K线按time字段做升序排序。TradingView要求返回的K线必须严格按时间从小到大排列,且覆盖请求指定的时间范围,否则会判定数据缺失,继续发起请求拉取更早的数据。 - 价格精度不匹配。异常数据集的价格在
1e-9量级,正常数据集价格在1e-5量级,如果初始化TradingView时配置的pricescale(价格精度)没有对应调整,过小的价格值会被判定为非法数据,触发重试。 - 回调参数缺失。返回有效K线时没有明确告知TradingView是否还有更早的历史数据,库会默认还有未拉取的更早数据,持续发起请求。
- 异常分支未触发正确回调。请求报错时只在本地打印日志,没有调用
onErrorCallback通知TradingView请求失败,库会因为没有收到明确的失败/成功回调持续挂起重试。 - 正常数据集场景下不打印日志,是因为该场景下数据符合规范,命中了TradingView的内置缓存,不需要重复调用
getBars方法,所以没有对应日志输出。
修复方案
按以下顺序调整代码即可解决问题:
- 处理接口返回的K线数据时,先根据
periodParams.from和periodParams.to过滤出落在请求时间范围内的K线,再将过滤后的数组按time字段从小到大做升序排序,剔除时间戳重复的异常K线。 - 初始化TradingView交易对配置时,根据币种价格量级设置对应的
pricescale:如果价格精度到9位小数,就把pricescale设为1e9,保证极小价格值能被正确识别。 - 调用
onHistoryCallback时,如果已经返回了当前请求范围内的所有K线、且没有更早的历史数据,要在第二个参数中补充nextTime字段,传入已返回K线中最早的时间戳,明确告知TradingView停止向前拉取历史数据。示例回调写法:
// 过滤、排序完成后的bars数组 if (bars.length) { // 取最早一根K线的时间作为nextTime const earliestTime = bars[0].time; onHistoryCallback(bars, { noData: false, nextTime: earliestTime // 告诉图表没有更早的数据了 }); } else { onHistoryCallback(bars, { noData: true }); }
- catch分支中补充
onErrorCallback(err)调用,明确通知TradingView本次请求失败,终止重试逻辑。
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

