{"record":{"id":"5d49f642e89bf429","repo":"flipped-aurora/gin-vue-admin","slug":"2xx-d","errorCode":null,"errorMessage":"非 2xx 响应: %d","messagePattern":"非 2xx 响应: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_timed_task_runner.go","lineNumber":170,"sourceCode":"\t\t\treq.Header.Set(k, v)\n\t\t}\n\t}\n\n\tclient := newTimedTaskHTTPClient(t.HttpAllowPrivate, defaultHTTPTimeout)\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tvar uerr *url.Error\n\t\tif errors.As(err, &uerr) && uerr.Timeout() {\n\t\t\treturn \"\", errTaskTimeout\n\t\t}\n\t\treturn \"\", err\n\t}\n\tdefer resp.Body.Close()\n\n\tdata, _ := io.ReadAll(io.LimitReader(resp.Body, maxHTTPRespBytes))\n\tout := fmt.Sprintf(\"HTTP %d: %s\", resp.StatusCode, string(data))\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn out, fmt.Errorf(\"非 2xx 响应: %d\", resp.StatusCode)\n\t}\n\treturn out, nil\n}\n\n// alertFailure 失败告警: 查 888 角色用户, 经本体 SSE Hub 定向推送(离线静默丢弃, 不阻塞)\nfunc (s *TimedTaskService) alertFailure(t system.SysTimedTask, errMsg string) {\n\tvar ids []uint\n\tif err := global.GVA_DB.Model(&system.SysUserAuthority{}).\n\t\tWhere(\"sys_authority_authority_id = ?\", alertAuthorityID).\n\t\tPluck(\"sys_user_id\", &ids).Error; err != nil {\n\t\tlogger.Bg().Mod(\"timedTask\").Err(err).Error(\"查询告警接收人失败\")\n\t\treturn\n\t}\n\tif len(ids) == 0 {\n\t\treturn\n\t}\n\tpayload, _ := json.Marshal(map[string]interface{}{\n\t\t\"taskId\": t.ID,","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_timed_task_runner.go#L152-L188","documentation":"runHTTP treats any response status outside 200-299 as a failed call. It still returns the output string ('HTTP <code>: <body>', body capped at maxHTTPRespBytes) but the error is 非 2xx 响应: <code>. This makes the timed task's status reflect endpoint-level failure, not just transport errors.","triggerScenarios":"The callback endpoint returned 4xx/5xx (400 bad payload, 401 auth failure, 404 wrong path, 500 server error).","commonSituations":"Callback URL expects an auth header that the http_header JSON no longer supplies; endpoint path changed after a deploy; target service temporarily down returning 502/503; payload rejected with 422.","solutions":["Check the recorded output for the status code and response body to see the remote error","Fix authentication/headers or payload so the endpoint returns 2xx","Verify the callback endpoint URL is still correct after refactors","If the endpoint is intermittently failing, fix or add retry handling at the target service"],"exampleFix":"// before\nheaders = {}\n// after (target expects auth)\nHttpHeader: '{\"Authorization\":\"Bearer <token>\"}'","handlingStrategy":"retry","validationCode":"// pre-check endpoint reachability before scheduling the task\nresp, err := http.Head(callbackURL)\nif err != nil || resp.StatusCode >= 400 {\n    log.Warn(\"callback endpoint unhealthy before scheduling\")\n}","typeGuard":null,"tryCatchPattern":"out, err := RunTask(t)\nif err != nil && strings.Contains(err.Error(), \"非 2xx 响应\") {\n    log.Errorf(\"callback %s returned failure. output: %s\", t.HttpUrl, out)\n    // inspect status code and body in out to fix auth/payload\n}","preventionTips":["Include required auth/headers in http_header so the endpoint returns 2xx","Monitor the alertFailure SSE notifications for repeated non-2xx codes","Pin down callback endpoint contracts and update task URLs after API refactors","Add retry/backoff at the endpoint or an intermediate queue for transient 5xx"],"tags":["http","status-code","timed-task","remote-endpoint"],"backgroundTag":"http-non-2xx-response","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}