{"record":{"id":"ec6d0410994f179b","repo":"binarywang/WxJava","slug":"secret-ec6d04","errorCode":null,"errorMessage":"通讯录同步secret未配置","messagePattern":"通讯录同步secret未配置","errorType":"validation","errorClass":"WxErrorException","httpStatus":null,"severity":"error","filePath":"weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java","lineNumber":95,"sourceCode":"  }\n\n  @Override\n  public String getContactAccessToken(boolean forceRefresh) throws WxErrorException {\n    if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {\n      return this.configStorage.getContactAccessToken();\n    }\n\n    Lock lock = this.configStorage.getContactAccessTokenLock();\n    lock.lock();\n    try {\n      // 拿到锁之后，再次判断一下最新的token是否过期，避免重刷\n      if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {\n        return this.configStorage.getContactAccessToken();\n      }\n      // 使用通讯录同步secret获取access_token\n      String contactSecret = this.configStorage.getContactSecret();\n      if (contactSecret == null || contactSecret.trim().isEmpty()) {\n        throw new WxErrorException(\"通讯录同步secret未配置\");\n      }\n      String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),\n        this.configStorage.getCorpId(), contactSecret);\n\n      try {\n        HttpGet httpGet = new HttpGet(url);\n        if (this.httpProxy != null) {\n          RequestConfig config = RequestConfig.custom()\n            .setProxy(this.httpProxy).build();\n          httpGet.setConfig(config);\n        }\n        String resultContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);\n        WxError error = WxError.fromJson(resultContent, WxType.CP);\n        if (error.getErrorCode() != 0) {\n          throw new WxErrorException(error);\n        }\n\n        WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/binarywang/WxJava/blob/1c43293a3c2c9d7e91304b6d037fb017f680d0c6/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java#L77-L113","documentation":"Thrown (as checked WxErrorException) by getContactAccessToken() in the HttpComponents (HttpClient 5) implementation when the contact-sync secret is null or blank. Identical logic to the Apache HttpClient variant, but in the newer HttpComponents-based service class.","triggerScenarios":"Any contact-sync operation via WxCpServiceHttpComponentsImpl when configStorage.getContactSecret() is null or whitespace-only.","commonSituations":"Switched from WxCpServiceImpl to WxCpServiceHttpComponentsImpl but the same config object lacks the contact secret; env var not set in the deployment using HttpComponents; multi-corp config where only some configs have contact secrets.","solutions":["Set the contact secret via configStorage.setContactSecret() during initialization","In Spring Boot, ensure wx.cp.contact-secret is configured regardless of which HTTP client implementation is active","Verify the secret is present in the environment for all deployments using the HttpComponents implementation"],"exampleFix":"// before — using HttpComponents impl without contact secret\nWxCpService service = new WxCpServiceHttpComponentsImpl();\nservice.setWxCpConfigStorage(config); // config.contactSecret == null\n\n// after\nconfig.setContactSecret(System.getenv(\"WX_CP_CONTACT_SECRET\"));\nservice.setWxCpConfigStorage(config);","handlingStrategy":"validation","validationCode":"// Validate contact secret regardless of HTTP client implementation\nString contactSecret = configStorage.getContactSecret();\nif (StringUtils.isBlank(contactSecret)) {\n  throw new IllegalStateException(\"通讯录同步 secret 未配置，请检查 application.yml 中的 wx.cp.contact-secret\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Secret configuration is implementation-agnostic — ensure it is set regardless of which WxCpService*Impl you use","Centralize config initialization so switching HTTP client implementations does not lose secrets","Add a startup validator that checks all required secrets"],"tags":["wechat-cp","config","contact-sync","access-token","secret","httpcomponents"],"backgroundTag":null,"analyzedSha":"1c43293a3c2c9d7e91304b6d037fb017f680d0c6","analyzedAt":"2026-08-14T02:29:11.060Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}