123 lines
4.4 KiB
Python
123 lines
4.4 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
目录接口诊断脚本 - 检查正式环境 soulapi 的 /api/miniprogram/book/* 是否正常
|
|||
|
|
用法:
|
|||
|
|
python scripts/test/check-catalog-api.py
|
|||
|
|
SOUL_TEST_ENV=soulapi python scripts/test/check-catalog-api.py
|
|||
|
|
"""
|
|||
|
|
import json
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# 加载测试配置
|
|||
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|||
|
|
from config import API_BASE, ENV_LABEL, get_env_banner
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
import urllib.request
|
|||
|
|
import urllib.error
|
|||
|
|
_urlopen = urllib.request.urlopen
|
|||
|
|
_Request = urllib.request.Request
|
|||
|
|
_HTTPError = urllib.error.HTTPError
|
|||
|
|
_URLError = urllib.error.URLError
|
|||
|
|
except ImportError:
|
|||
|
|
import urllib2
|
|||
|
|
_urlopen = urllib2.urlopen
|
|||
|
|
_Request = urllib2.Request
|
|||
|
|
_HTTPError = urllib2.HTTPError
|
|||
|
|
_URLError = urllib2.URLError
|
|||
|
|
|
|||
|
|
def fetch(url, timeout=10):
|
|||
|
|
"""GET 请求,返回 (parsed_json, status_code, error_msg)"""
|
|||
|
|
try:
|
|||
|
|
req = _Request(url)
|
|||
|
|
req.get_method = lambda: "GET"
|
|||
|
|
req.add_header("Content-Type", "application/json")
|
|||
|
|
resp = _urlopen(req, timeout=timeout)
|
|||
|
|
body = resp.read().decode("utf-8", errors="replace")
|
|||
|
|
code = getattr(resp, "status", resp.getcode() if hasattr(resp, "getcode") else 200)
|
|||
|
|
try:
|
|||
|
|
data = json.loads(body)
|
|||
|
|
except json.JSONDecodeError:
|
|||
|
|
return None, code, "非 JSON 响应: " + body[:200]
|
|||
|
|
return data, code, None
|
|||
|
|
except _HTTPError as e:
|
|||
|
|
try:
|
|||
|
|
body = e.read().decode("utf-8", errors="replace")
|
|||
|
|
data = json.loads(body) if body else {}
|
|||
|
|
except Exception:
|
|||
|
|
data = {}
|
|||
|
|
return data, e.code, str(e)
|
|||
|
|
except _URLError as e:
|
|||
|
|
return None, None, str(e.reason) if hasattr(e, "reason") else str(e)
|
|||
|
|
except Exception as e:
|
|||
|
|
return None, None, str(e)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
print(get_env_banner())
|
|||
|
|
base = API_BASE.rstrip("/")
|
|||
|
|
|
|||
|
|
endpoints = [
|
|||
|
|
("/api/miniprogram/book/parts", "目录-篇章列表(目录页主接口)"),
|
|||
|
|
("/api/miniprogram/book/all-chapters", "全书章节(app.loadBookData)"),
|
|||
|
|
("/health", "健康检查"),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
all_ok = True
|
|||
|
|
for path, desc in endpoints:
|
|||
|
|
url = base + path
|
|||
|
|
print(f"\n--- {desc} ---")
|
|||
|
|
print(f"URL: {url}")
|
|||
|
|
data, code, err = fetch(url)
|
|||
|
|
if err:
|
|||
|
|
print("[FAIL] 请求失败:", err)
|
|||
|
|
all_ok = False
|
|||
|
|
continue
|
|||
|
|
if code and code != 200:
|
|||
|
|
print("[FAIL] HTTP", code)
|
|||
|
|
if data:
|
|||
|
|
print(f" 响应: {json.dumps(data, ensure_ascii=False)[:300]}")
|
|||
|
|
all_ok = False
|
|||
|
|
continue
|
|||
|
|
if not data:
|
|||
|
|
print("[FAIL] 无响应体")
|
|||
|
|
all_ok = False
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
success = data.get("success")
|
|||
|
|
if path == "/health":
|
|||
|
|
status = data.get("status", "?")
|
|||
|
|
print("[OK] status=%s, version=%s" % (status, data.get("version", "?")))
|
|||
|
|
elif path == "/api/miniprogram/book/parts":
|
|||
|
|
parts = data.get("parts") or []
|
|||
|
|
total = data.get("totalSections", 0)
|
|||
|
|
fixed = data.get("fixedSections") or []
|
|||
|
|
print("[OK] success=%s, parts=%d, totalSections=%d, fixedSections=%d" % (success, len(parts), total, len(fixed)))
|
|||
|
|
if not parts and total == 0:
|
|||
|
|
print(" [WARN] 篇章为空! 请检查正式环境数据库 chapters 表")
|
|||
|
|
elif parts:
|
|||
|
|
print(" 首篇章: id=%s, title=%s" % (parts[0].get("id"), parts[0].get("title")))
|
|||
|
|
elif path == "/api/miniprogram/book/all-chapters":
|
|||
|
|
arr = data.get("data") or data.get("chapters") or []
|
|||
|
|
print("[OK] success=%s, data=%d 条" % (success, len(arr)))
|
|||
|
|
if not arr:
|
|||
|
|
print(" [WARN] 章节列表为空! 请检查 chapters 表")
|
|||
|
|
elif arr:
|
|||
|
|
first = arr[0] if isinstance(arr[0], dict) else {}
|
|||
|
|
print(" 首条: id=%s, partTitle=%s" % (first.get("id"), first.get("partTitle")))
|
|||
|
|
|
|||
|
|
print("\n" + "=" * 50)
|
|||
|
|
if all_ok:
|
|||
|
|
print("[OK] 所有接口正常,若小程序仍无法加载,请检查:")
|
|||
|
|
print(" 1. 微信公众平台 → 服务器域名 → request 合法域名 是否包含 soulapi.quwanzhi.com")
|
|||
|
|
print(" 2. 正式版小程序 baseUrl 是否为 https://soulapi.quwanzhi.com")
|
|||
|
|
else:
|
|||
|
|
print("[FAIL] 存在异常,请根据上述输出排查后端或数据库")
|
|||
|
|
print("=" * 50)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|