fix(web): v1.19.3 K线空body不再500 + SPA路由刷新404

两个独立问题(日志证据):

1. K线空body 500:SH600519 等正常股票偶发请求时,通达信返回
   ret_count>0 但 body 完全为空(偏移2 剩余0)。v1.18.3 的容错有
   'if bars:' 条件,bars 为空时 raise → 500。移除该条件,始终 return
   (空列表让前端分页重试比 500 友好)。GetIndexBarsCmd 同改。

2. SPA fallback 缺失:/optimize /portfolio 等前端路由刷新时 404。
   子类化 StaticFiles 为 SPAStaticFiles,404 时返回 index.html。
   API 路径不受影响。

测试:更新 test_security_bars_truncated_first_record(原断言 raise,
现断言返回空列表)+ 新增空 body 回归测试。902 全过。
This commit is contained in:
Justin Gu
2026-07-07 20:13:39 +08:00
parent 6b51487477
commit 032f5a40c0
6 changed files with 86 additions and 31 deletions
+9 -5
View File
@@ -144,10 +144,14 @@ def test_security_bars_truncated_drops_partial_last_record():
assert len(bars) == 4 # 前 4 条完整,末条残缺被丢弃
def test_security_bars_truncated_first_record_still_raises():
"""若连第一条都无法解析(body 完全没有记录数据),仍抛 TdxDecodeError。"""
def test_security_bars_truncated_first_record_returns_empty():
"""若连第一条都无法解析(body 完全没有记录数据),返回空列表而非抛异常。
v1.19.2 实测:SH600519 等正常股票偶发返回 ret_count>0 但 body 为空,
服务器侧问题。v1.18.3 的容错有 ``if bars:`` 条件导致此场景仍 raise → 500,
老人看到"取行情失败"。改为始终 return(空列表让前端分页重试比 500 好)。
"""
from easy_tdx.commands.security_bars import GetSecurityBarsCmd
from easy_tdx.exceptions import TdxDecodeError
from easy_tdx.models.enums import KlineCategory, Market
body = load_hex("security_bars")
@@ -157,8 +161,8 @@ def test_security_bars_truncated_first_record_still_raises():
truncated = struct.pack("<H", 5) + truncated[2:]
cmd = GetSecurityBarsCmd(Market.SH, "600000", KlineCategory.DAY, 0, 5)
with pytest.raises(TdxDecodeError):
cmd.parse_response(truncated)
bars = cmd.parse_response(truncated)
assert bars == []
# ---------------------------------------------------------------------------
+14
View File
@@ -97,3 +97,17 @@ def test_security_bars_complete_body_not_affected() -> None:
bars = cmd.parse_response(body)
assert len(bars) == 2
assert (bars[1].year, bars[1].month, bars[1].day) == (2024, 1, 2)
def test_security_bars_ret_count_lies_body_completely_empty() -> None:
"""ret_count 撒谎说有数据但 body 只有 ret_count 头(0 条记录数据)。
回归 v1.19.2 日志报错:SH600519 请求 count=800,服务器返回 ret_count=5
但 body 从 pos=2 开始就为空,第 1 条 datetime 解析即崩(偏移 2,剩余 0)。
v1.18.3 的容错有 ``if bars:`` 条件,bars 为空时走 ``raise`` → 500。
修复后无论 bars 是否为空都 return(空列表让调用方重试比 500 好)。
"""
body = struct.pack("<H", 5) # ret_count=5,但 0 字节记录数据
cmd = GetSecurityBarsCmd(Market.SH, "600519", KlineCategory.DAY, 0, 800)
bars = cmd.parse_response(body)
assert bars == []