binarywang/WxJava · error · WxErrorException

通讯录同步secret未配置

Error message

通讯录同步secret未配置

What it means

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.

Source

Thrown at weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java:95

  }

  @Override
  public String getContactAccessToken(boolean forceRefresh) throws WxErrorException {
    if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {
      return this.configStorage.getContactAccessToken();
    }

    Lock lock = this.configStorage.getContactAccessTokenLock();
    lock.lock();
    try {
      // 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
      if (!this.configStorage.isContactAccessTokenExpired() && !forceRefresh) {
        return this.configStorage.getContactAccessToken();
      }
      // 使用通讯录同步secret获取access_token
      String contactSecret = this.configStorage.getContactSecret();
      if (contactSecret == null || contactSecret.trim().isEmpty()) {
        throw new WxErrorException("通讯录同步secret未配置");
      }
      String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
        this.configStorage.getCorpId(), contactSecret);

      try {
        HttpGet httpGet = new HttpGet(url);
        if (this.httpProxy != null) {
          RequestConfig config = RequestConfig.custom()
            .setProxy(this.httpProxy).build();
          httpGet.setConfig(config);
        }
        String resultContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
        WxError error = WxError.fromJson(resultContent, WxType.CP);
        if (error.getErrorCode() != 0) {
          throw new WxErrorException(error);
        }

        WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Set the contact secret via configStorage.setContactSecret() during initialization
  2. In Spring Boot, ensure wx.cp.contact-secret is configured regardless of which HTTP client implementation is active
  3. Verify the secret is present in the environment for all deployments using the HttpComponents implementation

Example fix

// before — using HttpComponents impl without contact secret
WxCpService service = new WxCpServiceHttpComponentsImpl();
service.setWxCpConfigStorage(config); // config.contactSecret == null

// after
config.setContactSecret(System.getenv("WX_CP_CONTACT_SECRET"));
service.setWxCpConfigStorage(config);
Defensive patterns

Strategy: validation

Validate before calling

// Validate contact secret regardless of HTTP client implementation
String contactSecret = configStorage.getContactSecret();
if (StringUtils.isBlank(contactSecret)) {
  throw new IllegalStateException("通讯录同步 secret 未配置,请检查 application.yml 中的 wx.cp.contact-secret");
}

Prevention

When it happens

Trigger: Any contact-sync operation via WxCpServiceHttpComponentsImpl when configStorage.getContactSecret() is null or whitespace-only.

Common situations: 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.

Related errors


AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14). Data as JSON: /api/errors/ec6d0410994f179b. Report an issue: GitHub.