{"record":{"id":"7d10681551dd291d","repo":"JeffreySu/WeiXinMPSDK","slug":"nonce-str-ts","errorCode":null,"errorMessage":"预签名请求必须同时提供 nonce_str 和 ts。","messagePattern":"预签名请求必须同时提供 nonce_str 和 ts。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/PayTool/PayToolSignatureHelper.cs","lineNumber":47,"sourceCode":"        /// <summary>\n        /// 为收款工具请求补齐随机串、Unix 时间戳和数字签名。\n        /// 已提供签名时不会重新签名，并要求调用方同时提供原签名对应的随机串和时间戳。\n        /// </summary>\n        /// <param name=\"request\">需要签名的收款工具请求。</param>\n        /// <param name=\"payToolApiSecret\">收银台 API 调用密钥；请求未预签名时必填。</param>\n        public static void PrepareRequest(PayToolSignedRequestBase request,\n            string payToolApiSecret)\n        {\n            if (request == null)\n            {\n                throw new ArgumentNullException(nameof(request));\n            }\n\n            if (!string.IsNullOrEmpty(request.sig))\n            {\n                if (string.IsNullOrEmpty(request.nonce_str) || request.ts <= 0)\n                {\n                    throw new ArgumentException(\"预签名请求必须同时提供 nonce_str 和 ts。\",\n                        nameof(request));\n                }\n\n                return;\n            }\n\n            if (string.IsNullOrEmpty(payToolApiSecret))\n            {\n                throw new ArgumentException(\"请求未提供 sig 时必须提供收银台 API 调用密钥。\",\n                    nameof(payToolApiSecret));\n            }\n\n            if (string.IsNullOrEmpty(request.nonce_str))\n            {\n                request.nonce_str = Guid.NewGuid().ToString(\"N\");\n            }\n\n            if (request.ts <= 0)","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/PayTool/PayToolSignatureHelper.cs#L29-L65","documentation":"When a PayTool request already carries a signature (sig is non-empty), PrepareRequest requires the companion fields nonce_str and ts so the signature can be validated; it throws ArgumentException (预签名请求必须同时提供 nonce_str 和 ts。) if either nonce_str is empty or ts <= 0.","triggerScenarios":"Calling PrepareRequest on a request where request.sig is set but request.nonce_str is null/empty or request.ts is 0/negative — e.g. manually setting sig without filling nonce_str/ts, or deserializing a partially filled request.","commonSituations":"Reusing a request object across retries where nonce_str/ts were cleared; hand-crafting pre-signed requests in tests; binding from a form/JSON where ts was sent as a string and defaulted to 0; forgetting to set ts (Unix seconds) when supplying sig manually.","solutions":["Set both request.nonce_str (random string) and request.ts (current Unix timestamp in seconds) whenever request.sig is provided","If the request is not intentionally pre-signed, clear request.sig so PrepareRequest signs it using payToolApiSecret instead","Check deserialization/binding so ts is correctly populated as a positive integer"],"exampleFix":"// before\nreq.sig = ComputeSig(req); // sig set, but nonce_str/ts empty\nPayToolSignatureHelper.PrepareRequest(req, apiSecret);\n// after\nreq.nonce_str = Guid.NewGuid().ToString(\"N\");\nreq.ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();\nreq.sig = ComputeSig(req);\nPayToolSignatureHelper.PrepareRequest(req, apiSecret);","handlingStrategy":"validation","validationCode":"bool presignOk = string.IsNullOrEmpty(req.sig) || (!string.IsNullOrEmpty(req.nonce_str) && req.ts > 0);\nif (!presignOk) throw new InvalidOperationException(\"Pre-signed requests need both nonce_str and ts\");","typeGuard":"bool IsPreSigned(PayToolSignedRequestBase r) => !string.IsNullOrEmpty(r.sig);\nbool PreSignFieldsValid(PayToolSignedRequestBase r) => IsPreSigned(r) && !string.IsNullOrEmpty(r.nonce_str) && r.ts > 0;","tryCatchPattern":"try { PayToolSignatureHelper.PrepareRequest(req, apiSecret); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"nonce_str\")) { logger.LogError(ex, \"Pre-sign fields incomplete\"); req.sig = null; PayToolSignatureHelper.PrepareRequest(req, apiSecret); }","preventionTips":["Always set nonce_str and ts (Unix seconds) together whenever you set sig manually","Let PrepareRequest sign the request instead of hand-setting sig when possible","Verify ts binding from JSON/form input is a positive integer, not a defaulted 0"],"tags":["argument-validation","signature","payment","missing-field","wechat-work"],"backgroundTag":"missing-required-argument","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}