Ver Fonte

fix(ds): JSON 解析失败抛 raw response + CLI 加 -o 写文件

- api.py 包 try/except resp.json(),path 错被 SPA fallback 时
  错误信息含 response 前 200 字符,不再抛抽象 JSONDecodeError
- cli.py 加 -o <file>,避免大 JSON 在 ssh stdout 截断 / banner 污染

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tianyu.chu há 5 dias atrás
pai
commit
2cbd5cf9e2
2 ficheiros alterados com 20 adições e 3 exclusões
  1. 10 2
      dw_base/ds/api.py
  2. 10 1
      dw_base/ds/cli.py

+ 10 - 2
dw_base/ds/api.py

@@ -39,11 +39,19 @@ class DSClient:
         if resp.status_code // 100 != 2:
         if resp.status_code // 100 != 2:
             raise RuntimeError('GET {} failed rc={}: {}'.format(
             raise RuntimeError('GET {} failed rc={}: {}'.format(
                 path, resp.status_code, resp.text))
                 path, resp.status_code, resp.text))
-        return resp.json()
+        try:
+            return resp.json()
+        except ValueError:
+            raise RuntimeError('GET {} 返回非 JSON(可能 path 错被 SPA fallback): {}'.format(
+                path, resp.text[:200]))
 
 
     def post(self, path: str, json_body: Optional[Dict[str, Any]] = None) -> Any:
     def post(self, path: str, json_body: Optional[Dict[str, Any]] = None) -> Any:
         resp = self.session.post(self._url(path), json=json_body)
         resp = self.session.post(self._url(path), json=json_body)
         if resp.status_code // 100 != 2:
         if resp.status_code // 100 != 2:
             raise RuntimeError('POST {} failed rc={}: {}'.format(
             raise RuntimeError('POST {} failed rc={}: {}'.format(
                 path, resp.status_code, resp.text))
                 path, resp.status_code, resp.text))
-        return resp.json()
+        try:
+            return resp.json()
+        except ValueError:
+            raise RuntimeError('POST {} 返回非 JSON(可能 path 错被 SPA fallback): {}'.format(
+                path, resp.text[:200]))

+ 10 - 1
dw_base/ds/cli.py

@@ -36,10 +36,12 @@ def main():
     g = sub.add_parser('get', help='HTTP GET')
     g = sub.add_parser('get', help='HTTP GET')
     g.add_argument('path', help='API path,如 /projects')
     g.add_argument('path', help='API path,如 /projects')
     g.add_argument('-p', action='append', default=[], metavar='k=v', help='query 参数(可多次)')
     g.add_argument('-p', action='append', default=[], metavar='k=v', help='query 参数(可多次)')
+    g.add_argument('-o', dest='output', default=None, metavar='FILE', help='写 JSON 到文件(不打 stdout)')
 
 
     p = sub.add_parser('post', help='HTTP POST')
     p = sub.add_parser('post', help='HTTP POST')
     p.add_argument('path')
     p.add_argument('path')
     p.add_argument('-j', dest='body', default=None, metavar='JSON', help='JSON body')
     p.add_argument('-j', dest='body', default=None, metavar='JSON', help='JSON body')
+    p.add_argument('-o', dest='output', default=None, metavar='FILE', help='写 JSON 到文件(不打 stdout)')
 
 
     args = parser.parse_args()
     args = parser.parse_args()
     client = DSClient()
     client = DSClient()
@@ -50,7 +52,14 @@ def main():
         body = json.loads(args.body) if args.body else None
         body = json.loads(args.body) if args.body else None
         result = client.post(args.path, json_body=body)
         result = client.post(args.path, json_body=body)
 
 
-    print(json.dumps(result, ensure_ascii=False, indent=2))
+    text = json.dumps(result, ensure_ascii=False, indent=2)
+    if args.output:
+        with open(args.output, 'w', encoding='utf-8') as f:
+            f.write(text)
+            f.write('\n')
+        sys.stderr.write('[ds.cli] 已写到 {}\n'.format(args.output))
+    else:
+        print(text)
 
 
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':