You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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')  

修复方案

问题分析

  1. PUT请求URL错误:更新单个服务连接的URL需要包含具体的endpoint ID,不能用列表接口的通用URL。
  2. 请求体格式错误:Azure DevOps API直接接受服务连接对象作为请求体,不需要额外包裹body键。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:44:55