Zephyr Squad REST API导出Cycle为CSV时提示projectId参数缺失
调用Zephyr Squad Cycle导出API时提示"Missing parameter: projectId"的解决方法
问题分析
你遇到的核心问题是:Zephyr Squad的Cycle导出API(GET请求)要求参数通过URL查询参数传递,但你错误地将参数放在了JSON请求体中。GET请求规范通常不支持携带请求体,服务端无法识别你传入的projectId参数,因此报错。另外你生成的CANONICAL_PATH虽然包含查询参数,但实际请求并未在URL中带上这些参数,导致签名验证与实际请求不匹配,进一步引发参数校验失败。
解决方案
需要做以下几点修改:
- 将请求参数从JSON请求体移到URL查询参数中传递
- 确保
CANONICAL_PATH的生成与实际请求的查询参数完全一致(包括参数顺序,因为QSH签名基于该路径生成) - 使用
requests.get的params参数传递查询参数,而非json参数
修改后的完整代码
import json import jwt import time import hashlib import requests def is_json(data): try: json.loads(data) except ValueError: return False return True # USER ACCOUNT_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx' # ACCESS KEY from navigation >> Tests >> API Keys ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # SECRET KEY from navigation >> Tests >> API Keys SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' # JWT EXPIRE how long token been to be active? 3600 == 1 hour JWT_EXPIRE = 3600 # BASE URL for Zephyr for Jira Cloud BASE_URL = 'https://prod-api.zephyr4jiracloud.com/connect' # RELATIVE PATH for token generation and make request to api cycle_id = 'ca55798e-e9e8-4ebb-8b43-efac9360e615' RELATIVE_PATH = '/public/rest/api/1.0/cycle/{}/export'.format(cycle_id) # 定义查询参数,注意参数顺序要和CANONICAL_PATH中的一致 query_params = { 'projectId': '10000', 'versionId': '10000', 'exportType': 'CSV', 'folderId': 'UI' } # 构建CANONICAL_PATH:按照参数顺序拼接成查询字符串 query_str = '&'.join([f"{k}={v}" for k, v in query_params.items()]) CANONICAL_PATH = f'GET&{RELATIVE_PATH[1:]}?{query_str}' # TOKEN HEADER: to generate jwt token payload_token = { 'sub': ACCOUNT_ID, 'qsh': hashlib.sha256(CANONICAL_PATH.encode('utf-8')).hexdigest(), 'iss': ACCESS_KEY, 'exp': int(time.time())+JWT_EXPIRE, 'iat': int(time.time()) } # GENERATE TOKEN token = jwt.encode(payload_token, SECRET_KEY, algorithm='HS256').strip() # REQUEST HEADER: to authenticate and authorize api headers = { 'Authorization': 'JWT '+token, 'zapiAccessKey': ACCESS_KEY } # MAKE REQUEST: 使用params传递查询参数,不再传json raw_result = requests.get(BASE_URL + RELATIVE_PATH, headers=headers, params=query_params) print(raw_result) # Download the CSV file and save it to disk with open("Export.csv", "w", newline="", encoding='utf-8') as csvfile: csvfile.write(raw_result.text) if is_json(raw_result.text): # JSON RESPONSE: convert response to JSON json_result = json.loads(raw_result.text) # PRINT RESPONSE: pretty print with 4 indent print(json.dumps(json_result, indent=4, sort_keys=True)) else: print(raw_result.text)
关键修改点说明
- 参数传递方式:用
params参数替代json参数,将所有请求参数放在URL查询参数中,符合GET请求规范,也匹配Zephyr API的要求。 - CANONICAL_PATH一致性:确保生成的规范路径和实际请求的URL查询参数完全一致,包括参数顺序,这样JWT签名的QSH(Query String Hash)才能通过验证。
- 优化文件保存:添加
encoding='utf-8'避免CSV文件出现乱码问题。
内容的提问来源于stack exchange,提问作者Nɪsʜᴀɴᴛʜ ॐ
相关产品推荐
相关产品推荐

