{"record":{"id":"7c99d2cb97c5ce3d","repo":"jeessy2/ddns-go","slug":"v-7c99d2","errorCode":null,"errorMessage":"生成签名失败: %v","messagePattern":"生成签名失败: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns/nowcn.go","lineNumber":241,"sourceCode":"\n\t// 6. 重新构造最终的查询字符串(包含签名)\n\tkeys = append(keys, \"Signature\")\n\tsort.Strings(keys)\n\tvar finalQuery []string\n\tfor _, k := range keys {\n\t\tencodedKey := util.PercentEncode(k)\n\t\tencodedValue := util.PercentEncode(params[k])\n\t\tfinalQuery = append(finalQuery, encodedKey+\"=\"+encodedValue)\n\t}\n\n\treturn strings.Join(finalQuery, \"&\"), nil\n}\n\nfunc (t *Nowcn) request(apiPath string, params map[string]string, method string) ([]byte, error) {\n\t// 生成签名\n\tqueryString, err := t.sign(params, method)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"生成签名失败: %v\", err)\n\t}\n\n\t// 构造完整URL\n\tbaseURL := \"https://api.now.cn\"\n\tfullURL := baseURL + apiPath + \"?\" + queryString\n\n\t// 创建HTTP请求\n\treq, err := http.NewRequest(method, fullURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建请求失败: %v\", err)\n\t}\n\n\t// 设置请求头\n\treq.Header.Set(\"Accept\", \"application/json\")\n\n\t// 发送请求\n\tclient := t.httpClient\n\tresp, err := client.Do(req)","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/dns/nowcn.go#L223-L259","documentation":"Nowcn.request builds a signed query string via t.sign before every API call; if signing fails the error is wrapped in Chinese ('签名生成失败' = signature generation failed). This is a pre-flight failure — no HTTP request is made, so create/modify/getRecordList cannot proceed.","triggerScenarios":"t.sign returns an error — typically a missing/empty API key or secret in the Nowcn credentials, or an unsupported method passed to the signature algorithm.","commonSituations":"Credentials not loaded from config/environment (empty accessKey/secretKey), misconfigured provider credentials block, or a code path passing an unexpected HTTP method into sign.","solutions":["Verify the Nowcn API key/secret are set and non-empty in configuration","Check that sign() is receiving the expected method and params","Log the underlying error from t.sign to pinpoint the missing credential","Re-generate provider credentials if they were rotated/revoked"],"exampleFix":"// before\nqueryString, err := t.sign(params, method)\nif err != nil {\n    return nil, fmt.Errorf(\"生成签名失败: %v\", err)\n}\n// after (guard credentials before calling request)\nif t.accessKey == \"\" || t.secretKey == \"\" {\n    return nil, errors.New(\"nowcn: accessKey/secretKey not configured\")\n}\nqueryString, err := t.sign(params, method)\nif err != nil {\n    return nil, fmt.Errorf(\"生成签名失败: %w\", err)\n}","handlingStrategy":"validation","validationCode":"// Go: fail fast on missing credentials before any request\nif t.accessKey == \"\" || t.secretKey == \"\" {\n    return errors.New(\"nowcn: accessKey and secretKey must be configured\")\n}","typeGuard":"func (t *Nowcn) credentialsOK() bool {\n    return t.accessKey != \"\" && t.secretKey != \"\"\n}","tryCatchPattern":"body, err := nowcnClient.request(apiPath, params, \"GET\")\nif err != nil {\n    if strings.Contains(err.Error(), \"生成签名失败\") {\n        return fmt.Errorf(\"signature failure — check nowcn credentials: %w\", err)\n    }\n    return err\n}","preventionTips":["Load and sanity-check credentials at startup, not per-request","Never pass empty/nil params maps to sign","Keep credential loading in one tested place","Rotate and re-verify credentials after provider-side changes"],"tags":["dns","signature","authentication","configuration"],"backgroundTag":"signature-generation-failed","analyzedSha":"5874c2e6667c69357ab95079421131104bd3fcae","analyzedAt":"2026-09-03T15:41:16.799Z","contentChangedAt":"2026-09-03T15:41:16.799Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}