调用API更新Azure DevOps CFD组件后Web界面报错
问题
我编写了Python代码,通过Azure DevOps的Dashboard Widget更新API自动修改Cumulative Flow Diagram(CFD)组件的设置,使其显示过去14、15、16天的数据。API请求返回成功,但Web界面打开时抛出错误:
TypeError: e.split is not a function
尝试改用多行格式设置时,又出现了SyntaxError。以下是相关代码,请问如何修复该问题?
主代码
import fazer_requisicoes import json import base64 import os from dotenv import load_dotenv from pprint import pp load_dotenv() token_do_azure = os.environ['AZURE_DEVOPS_PAT'] pat_encoded = base64.b64encode((":" + token_do_azure).encode()).decode() headers = { 'Content-Type': 'application/json', 'Authorization': f'Basic {pat_encoded}' } settings_dict = { "chartDataSettings": { "timePeriod": { "settings": 16 } } } def atualizar_cfd(): organization = 'dummy' project = 'dummy' team = 'dummy' dashboard_id = 'dummy' widget_id = 'dummy' url = f'https://dev.azure.com/{organization}/{project}/{team}/_apis/dashboard/dashboards/{dashboard_id}/widgets/{widget_id}?api-version=7.2-preview.2' get_req = fazer_requisicoes.fazer_requisicoes("GET", url, headers) get_req_text = json.loads(get_req.text) # 假设ETag在响应体中,否则从headers获取 current_etag_widget = get_req_text['eTag'] current_etag_dashboard = get_req_text['dashboard']['eTag'] pp(current_etag_widget) pp(current_etag_dashboard) url = f'https://dev.azure.com/{organization}/{project}/{team}/_apis/dashboard/dashboards/{dashboard_id}/widgets/{widget_id}?api-version=7.2-preview.2' req_body = { "id": widget_id, "name": "Cumulative Flow Diagram (CFD)", "eTag": f'{current_etag_widget}', 'position': {'row': 4, 'column': 5}, "size": { "rowSpan": 2, "columnSpan": 3 }, 'settings': settings_dict, "settingsVersion": { "major": 1, "minor": 0, "patch": 0 }, "contributionId": "ms.vss-dashboards-web.Microsoft.VisualStudioOnline.Dashboards.CumulativeFlowDiagramWidget", 'dashboard': {'position': -1, 'eTag': f'{current_etag_dashboard}', 'modifiedDate': '0001-01-01T00:00:00', 'lastAccessedDate': '0001-01-01T00:00:00'}, } req = fazer_requisicoes.fazer_requisicoes("PATCH", url, headers, req_body) req_text = json.loads(req.text) req_response = json.dumps(req_text) pp(req_response) def main(): atualizar_cfd() main()
请求函数代码
import requests import time import urllib3 from requests.exceptions import JSONDecodeError from pprint import pprint urllib3.disable_warnings() session = requests.Session() contador_timeout = 0 contador_SSL = 0 def fazer_requisicoes(metodo, url, headers, request_body=None): global contador_timeout global contador_SSL while True: try: if metodo in ['GET', 'DELETE']: req = session.request(metodo, url, headers=headers, verify=False) else: req = session.request(metodo, url, headers=headers, json=request_body, verify=False) try: req.json() except JSONDecodeError: print(f'{req.status_code}\n') pprint(req.text) print(f"收到无效响应,重试中...") time.sleep(10) continue return req except requests.exceptions.ConnectTimeout as e: contador_timeout += 1 print(f"第{contador_timeout}次超时错误,重试中...") time.sleep(10) except requests.exceptions.SSLError as e: contador_SSL += 1 print(f"第{contador_SSL}次SSL错误,重试中...") time.sleep(10)
解决方案
1. 修正CFD组件的设置结构
Web界面的TypeError: e.split is not a function错误,是因为前端期望处理字符串类型的配置值,但你传入了数字类型。同时CFD组件的timePeriod配置必须明确指定类型,否则前端无法识别格式。
修改settings_dict为以下结构:
settings_dict = { "chartDataSettings": { "timePeriod": { "type": "daysBack", # 指定时间范围类型为回溯天数 "settings": "16" # 改为字符串类型,匹配前端处理逻辑 } } }
2. 复用正确的settingsVersion
CFD组件的配置版本可能存在兼容性要求,手动指定的major:1可能不匹配。建议从GET请求返回的widget数据中直接复用现有版本:
# 在GET请求后添加 current_settings_version = get_req_text['settingsVersion']
然后在请求体中替换手动指定的版本:
"settingsVersion": current_settings_version,
3. 简化请求体中的dashboard字段
请求体中的dashboard字段仅需传入eTag即可,多余的字段可能引发前端解析异常:
'dashboard': {'eTag': current_etag_dashboard},
完整修改后的主代码片段
# ... 其他代码保持不变 ... def atualizar_cfd(): organization = 'dummy' project = 'dummy' team = 'dummy' dashboard_id = 'dummy' widget_id = 'dummy' url = f'https://dev.azure.com/{organization}/{project}/{team}/_apis/dashboard/dashboards/{dashboard_id}/widgets/{widget_id}?api-version=7.2-preview.2' get_req = fazer_requisicoes.fazer_requisicoes("GET", url, headers) get_req_text = json.loads(get_req.text) current_etag_widget = get_req_text['eTag'] current_etag_dashboard = get_req_text['dashboard']['eTag'] current_settings_version = get_req_text['settingsVersion'] # 复用现有版本号 pp(current_etag_widget) pp(current_etag_dashboard) # 修正后的设置 settings_dict = { "chartDataSettings": { "timePeriod": { "type": "daysBack", "settings": "16" } } } req_body = { "id": widget_id, "name": "Cumulative Flow Diagram (CFD)", "eTag": current_etag_widget, 'position': {'row': 4, 'column': 5}, "size": {"rowSpan": 2, "columnSpan": 3}, 'settings': settings_dict, "settingsVersion": current_settings_version, "contributionId": "ms.vss-dashboards-web.Microsoft.VisualStudioOnline.Dashboards.CumulativeFlowDiagramWidget", 'dashboard': {'eTag': current_etag_dashboard}, # 简化dashboard字段 } req = fazer_requisicoes.fazer_requisicoes("PATCH", url, headers, req_body) req_text = json.loads(req.text) req_response = json.dumps(req_text) pp(req_response)
修复原理
- 添加
timePeriod.type字段:明确告知CFD组件使用"回溯天数"的时间范围类型,符合前端解析逻辑。 - 将
settings值改为字符串:前端代码依赖字符串的split方法处理配置,数字类型会触发类型错误。 - 复用现有
settingsVersion:避免因版本不匹配导致的配置兼容性问题。 - 简化
dashboard字段:只保留必要的eTag,减少无关字段引发的解析异常。
内容的提问来源于stack exchange,提问作者fcoalcantarajr
相关产品推荐
相关产品推荐

