Files
HHY 7554f2e3c7 feat: 整站全量采集与订单写入接口契约补全
- GET 全量扫描 279 个接口并留档(HTTP200=90, 业务成功=76)
- POST 安全探测 24 个只读/计算接口(白名单制, 支付/短信/删除类零触碰)
- 订单写入接口契约经 chunk 源码静态分析补全:
  orders CRUD / 创建订单{contract_id,drawing_data,pic_url} / windoor_default 保存
- 确认付费墙语义 code=10086 及到期/角色权限响应
- doc/API.md 新增整站采集结果章节, 更新订单模块契约表
2026-09-20 07:19:10 -07:00

64 lines
3.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""POST 安全探测:仅探测搜索/计算/详情语义的接口(空最小请求体)。
绝不触碰:支付、短信、账号绑定、删除/更新类、文件上传类接口。"""
import json, os, re, time, urllib.request, urllib.error
BASE = "https://zzc-serv.thinkerx.com/api/"
TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvenpjLXNlcnYudGhpbmtlcnguY29tXC9hcGlcL3dlY2hhdC1sb2dpbi13aXRoLXBob25lIiwiaWF0IjoxNzg5OTA5NTIwLCJleHAiOjE3ODk5OTU5MjAsIm5iZiI6MTc4OTkwOTUyMCwianRpIjoiTGVyV0J4VTZONTVOMlNwQSIsInN1YiI6MzU2Mjg1NiwicHJ2IjoiNTRjMjZlNjE2MjNhYTQzMzZkZTQ1YTcxNGIwYzdhYWIxZTJhYzA3NSJ9.MXBrpBh3gseq8I91EQklxsgLfHafUKwNxc24JdcUkcc"
OUT = r"D:\Code\huamenchuang\data\full-site\post"
os.makedirs(OUT, exist_ok=True)
# 只读/计算语义白名单(详情查询、列表搜索、纯计算、受付费墙保护)
SAFE_POST = [
"orders/", "sunny_house_order/", "after_sales_orders/", "windoor_default",
"order-by-pid", "get_order_process", "record_by_contract_id",
"contract_bars_with_stock", "contract_share", "contract_share/",
"cut_solution", "offer-price", "offer-price/",
"optimize1d-ai", "optimize1d-test", "three-d-data",
"product_by_warehouse", "product-order-format", "product-order-format/",
"order_format_by_warehouse", "is-repeat-order", "cj-orders-status",
"xf_contract_workshop", "ai_product",
]
def safe_name(ep):
return re.sub(r'[^A-Za-z0-9_-]', '_', ep).strip('_') or 'root'
manifest = []
for ep in SAFE_POST:
body = json.dumps({"page": 1}).encode()
req = urllib.request.Request(BASE + ep, method="POST", headers={
"Authorization": f"Bearer {TOKEN}",
"X-Requested-With": "XMLHttpRequest",
"Accept": "application/json",
"Content-Type": "application/json",
}, data=body)
try:
with urllib.request.urlopen(req, timeout=20) as r:
status, text = r.status, r.read().decode("utf-8", "replace")
except urllib.error.HTTPError as e:
status, text = e.code, e.read().decode("utf-8", "replace")[:4000]
except Exception as e:
status, text = -1, str(e)[:200]
entry = {"endpoint": ep, "method": "POST", "status": status, "size": len(text)}
try:
j = json.loads(text)
if isinstance(j, dict):
entry["code"] = j.get("code")
entry["message"] = (j.get("message") or "")[:50]
entry["data_type"] = type(j.get("data")).__name__
# 记录校验错误里的字段清单(Laravel validation)
if j.get("errors"):
entry["required_fields"] = list(j["errors"].keys())
if j.get("data") and isinstance(j.get("data"), list):
entry["data_len"] = len(j["data"])
except Exception:
pass
json.dump({"endpoint": ep, "status": status, "body": text[:100000]},
open(f"{OUT}\\{safe_name(ep)}.json", "w", encoding="utf-8"), ensure_ascii=False)
manifest.append(entry)
print(f"{ep:38s} HTTP {status} code={entry.get('code')} {entry.get('message','')}", flush=True)
time.sleep(0.3)
json.dump(manifest, open(r"D:\Code\huamenchuang\data\full-site\post-manifest.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1)
print(f"\n完成: {len(SAFE_POST)} 个 POST 探测")