Python更新Azure DevOps服务连接报错:endpoint参数不可为null
问题:Azure DevOps服务连接更新PUT请求报错(Value cannot be null: endpoint)
我用Python写了个函数更新Azure DevOps服务连接的密钥,Postman里测试PUT请求完全正常,但Python代码执行时一直报以下错误:
{"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: endpoint","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
我的代码如下:
def update_sc_key(secret_value, app_name, sc_dependence): print(f"SC DEPENDENCE:", sc_dependence) personal_access_token = get_pat() bearer = get_bearer() if sc_dependence == True: pat_credentials = BasicAuthentication('', personal_access_token) connection = Connection(base_url=organization_url, creds=pat_credentials) service_connection_name = app_name[len('SP_') + app_name[len('SP_'):].find('_') - 4:] print(service_connection_name) service_endpoint_client = connection.clients.get_service_endpoint_client() service_connections = service_endpoint_client.get_service_endpoints(project_name) for service_connection in service_connections: if service_connection.name == "RENEWAL_SC_TEST": # service_connection_name print(f'SERVICE CONNECTION NAME:', service_connection.name) service_connection_id = service_connection.id print(f'SERVICE CONNECTION ID:', service_connection_id) # Get Service Connection body project_url = organization_url + project_name + "/_apis/serviceendpoint/endpoints" try: # GET RESPONSE get_params = { "endpointIds": service_connection_id, "api-version": "7.1-preview.4" } get_headers={ "Authorization": "Bearer " + bearer } get_response = requests.get(project_url, params=get_params, headers=get_headers) get_response_tr = get_response.json() get_data_obj1 = get_response_tr['value'] get_data_obj2 = str(get_data_obj1) get_data_obj3 = get_data_obj2[1:-1] if get_response.status_code == 200: get_data_obj_mod = get_data_obj3.replace("'authenticationType': 'spnKey'", "'authenticationType': 'spnKey', 'serviceprincipalkey': '" + secret_value + "'") get_data_obj_mod_rep = get_data_obj_mod.replace("'", "\"").replace("True", "true").replace("False", "false") get_data_obj_mod_rep = json.load(get_data_obj_mod) print(get_data_obj_mod_rep) else: print(f"Error: {get_response.status_code} - {get_response.text}") # PUT RESPONSE TO CHANGE PWD put_params = { "endpointId": service_connection_id, "api-version": "7.1-preview.4" } put_headers={ "Authorization": "Bearer " + bearer, "Content-Type": "application/json" } put_body={ "body": get_data_obj_mod_rep } put_response = requests.put(project_url, params=put_params, headers=put_headers, data=put_body) print(put_response.status_code) print(put_response.text) except json.JSONDecodeError as e: print("ERROR: expired bearer token") else: print(f'No Service Connection')
修复方案
问题分析
- PUT请求URL错误:更新单个服务连接的URL需要包含具体的endpoint ID,不能用列表接口的通用URL。
- 请求体格式错误:Azure DevOps API直接接受服务连接对象作为请求体,不需要额外包裹
body键。 - GET响应处理逻辑冗余且易出错:通过字符串替换修改JSON数据风险高,直接操作字典更可靠。
修复后的关键代码部分
# 修正GET响应处理逻辑 if get_response.status_code == 200: # 直接取第一个服务连接对象,跳过冗余的字符串转译 get_data_obj_mod = get_response_tr['value'][0] # 直接修改目标字段 get_data_obj_mod['serviceprincipalkey'] = secret_value print(get_data_obj_mod) else: print(f"Error: {get_response.status_code} - {get_response.text}") # 修正PUT请求部分 # 构造正确的更新URL:拼接endpoint ID put_url = f"{project_url}/{service_connection_id}" put_params = { "api-version": "7.1-preview.4" } put_headers={ "Authorization": "Bearer " + bearer, "Content-Type": "application/json" } # 直接使用修改后的服务连接对象作为请求体 put_body = get_data_obj_mod # 使用json参数自动序列化字典,避免手动格式处理 put_response = requests.put(put_url, params=put_params, headers=put_headers, json=put_body) print(put_response.status_code) print(put_response.text)
其他优化点
- 移除了不必要的字符串转译操作,直接操作字典更安全高效。
- 利用
requests.put的json参数自动完成字典到JSON字符串的转换,无需手动处理data参数。 - 调整PUT请求URL为单个服务连接的专属端点,符合Azure DevOps API的规范。
内容的提问来源于stack exchange,提问作者gjgjgjgj14
相关产品推荐
相关产品推荐

