调用GitHub API创建Issue返回HTTP 400 Bad Request错误
问题现象
编写push操作完成后自动创建Issue的自动化脚本时,GitHub API返回400错误,完全相同的代码此前可正常运行,无法定位问题出在代码逻辑还是API规则层面。
原实现代码
for ((i=0;i<${#arr_libraryNames[@]};++i)) do httpResponse=$(\ curl \ -H "Authorization: token ${OAuthToken}"\ https://api.github.com/repos/tpazhaidam/${arr_libraryNames[i]}/issues\ -d "{\"title\":\"Library Requires Template Update\",\"body\":\"When possible please update libraries to the most recent template version.\",\"assignees\":[\"tpazhaidam\"],\"labels\":[\"template update\"]}"\ -H "Accept: $API_VER_ACCEPTS"\ -X POST\ ) if [ "$httpResponse" != "201" ]; then echo "Failed to create issue for ${arr_libraryNames[i]} on GitHub" echo "HTTP Response $httpResponse" exit 1 else echo "OK" fi done
收到的HTTP错误响应
HTTP Response <html> <head> <meta content="origin" name="referrer"> <title>Bad request · GitHub</title> <meta name="viewport" content="width=device-width"> <style type="text/css" media="screen"> body { background-color: #f6f8fa; color: rgba(0, 0, 0, 0.5); font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; } .c { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { text-decoration: none; } a:hover { text-decoration: underline; } h1 { color: #24292e; line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; } p { margin: 20px 0 40px; } #s { margin-top: 35px; } #s a { color: #666666; font-weight: 200; font-size: 14px; margin: 0 10px; } </style> </head> <body> <div class="c"> <h1>Whoa there!</h1> <p>You have sent an invalid request. <br><br> Please do not send this request again. </p> <div id="s"> <a href="https://support.github.com">Contact Support</a> — <a href="https://githubstatus.com">GitHub Status</a> — <a href="https://twitter.com/githubstatus">@githubstatus</a> </div> </div> </body> </html>
问题根因
三个问题直接触发400拦截,都是早期API校验宽松时可正常运行、近期校验规则收紧后直接报错的典型情况:
- 响应判断逻辑从根上错了:当前代码把curl输出的完整响应正文存在
httpResponse变量里,却拿它和HTTP状态码201做对比。curl默认不会输出HTTP状态码,变量里存的永远是接口返回的正文内容,永远不可能匹配上"201",之前能正常运行大概率是旧版本脚本加了状态码提取参数,后续修改时被误删了。 - 缺少必填请求头:调用GitHub创建Issue接口传输JSON数据时,必须显式携带
Content-Type: application/json请求头。现在GitHub API对请求格式校验比之前严格,缺这个头的请求会直接被边缘防护拦截,返回通用400 HTML错误页,不会返回结构化的JSON错误信息,很难直接定位问题。 - shell语法存在隐性bug:原代码里
-X POST\这一行的反斜杠后面带了多余的空格,shell中行尾用于续行的反斜杠后不能跟任何空格、制表符,否则转义失效,后面的参数会被截断,直接导致请求格式非法。另外手动转义JSON双引号的写法容错率极低,只要传入的仓库名、参数里带特殊字符、空格,就会导致JSON格式错误。
修正后的可运行代码
for ((i=0;i<${#arr_libraryNames[@]};++i)) do # 用here-document定义JSON载荷,无需手动转义双引号,避免格式错误 issue_payload=$(cat <<EOF { "title": "Library Requires Template Update", "body": "When possible please update libraries to the most recent template version.", "assignees": ["tpazhaidam"], "labels": ["template update"] } EOF ) # 发请求:-s静默输出进度条,-w单独提取HTTP状态码做判断,加必填的Content-Type头,响应正文存入临时文件方便排查 http_code=$(curl -s -w "%{http_code}" \ -H "Authorization: token ${OAuthToken}" \ -H "Accept: ${API_VER_ACCEPTS}" \ -H "Content-Type: application/json" \ -d "$issue_payload" \ -X POST \ "https://api.github.com/repos/tpazhaidam/${arr_libraryNames[i]}/issues" \ -o /tmp/github_issue_resp.tmp) if [ "$http_code" != "201" ]; then echo "Failed to create issue for ${arr_libraryNames[i]} on GitHub" echo "HTTP Status Code: $http_code" echo "Error response content:" cat /tmp/github_issue_resp.tmp rm -f /tmp/github_issue_resp.tmp exit 1 else echo "Created issue for ${arr_libraryNames[i]} successfully" rm -f /tmp/github_issue_resp.tmp fi done
额外注意点
- 所有行尾用于续行的反斜杠后面不要加任何空格,写完直接敲回车换行即可,避免转义失效。
- 如果个人访问令牌(OAuthToken)是新生成的,要确认勾选了
repo范围的权限,否则也会出现请求被拦截的情况。
内容的提问来源于stack exchange,提问作者Thomas Pazhaidam
相关产品推荐
相关产品推荐

