binarywang/WxJava · error · WxErrorException

签名错误

Error message

签名错误

What it means

Thrown by the 2-arg getUserEncryptKey(openid, sessionKey) when the local HMAC-SHA256 computation in sha256("", sessionKey) raises any exception; the catch block swallows the real cause and rethrows a generic WxErrorException("签名错误"). This is a CLIENT-SIDE signature computation failure, not a WeChat server rejection. The sha256 helper calls sessionKey.getBytes(StandardCharsets.UTF_8), so a null sessionKey is the dominant trigger; Mac.getInstance("HmacSHA256") failure is effectively impossible on a standard JVM.

Source

Thrown at weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java:51

    for (byte item : array) {
      sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
    }
    return sb.toString().toUpperCase();
  }

  @Override
  public WxMaInternetResponse getUserEncryptKey(String openid, String signature, String sigMethod) throws WxErrorException {
    String url = WxMaApiUrlConstants.Internet.GET_USER_ENCRYPT_KEY + "?openid=" + openid + "&signature=" + signature + "&sig_method=" + sigMethod;
    return getWxMaInternetResponse(url);
  }

  @Override
  public WxMaInternetResponse getUserEncryptKey(String openid, String sessionKey) throws WxErrorException {
    String signature = null;
    try {
      signature = sha256("", sessionKey);
    } catch (Exception e) {
      throw new WxErrorException("签名错误");
    }
    String url = WxMaApiUrlConstants.Internet.GET_USER_ENCRYPT_KEY + "?sig_method=hmac_sha256&openid=" + openid + "&signature=" + signature;
    return getWxMaInternetResponse(url);
  }

  private WxMaInternetResponse getWxMaInternetResponse(String url) throws WxErrorException {
    String responseContent = this.wxMaService.post(url, "");
    WxMaInternetResponse response = WxMaGsonBuilder.create().fromJson(responseContent, WxMaInternetResponse.class);
    if (response.getErrcode() != null && response.getErrcode() != 0) {
      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
    }
    return response;
  }
}

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Ensure sessionKey is non-null by obtaining it fresh via wxMaService.getUserService().getSessionInfo(jsCode) (jscode2session) immediately before calling getUserEncryptKey.
  2. Guard the input: if sessionKey is null/blank, re-run the mini-program login flow instead of calling getUserEncryptKey.
  3. Cache sessionKey with a TTL under WeChat's expiry and refresh when it returns null.

Example fix

// before
WxMaInternetResponse resp = internetService.getUserEncryptKey(openid, sessionKey);

// after
if (sessionKey == null || sessionKey.trim().isEmpty()) {
  throw new IllegalStateException("sessionKey 缺失,请重新登录");
}
WxMaInternetResponse resp = internetService.getUserEncryptKey(openid, sessionKey);
Defensive patterns

Strategy: validation

Validate before calling

if (sessionKey == null || sessionKey.trim().isEmpty()) {
  throw new IllegalArgumentException("sessionKey 不能为空,请先调用 jscode2session");
}

Try / catch

try {
  response = internetService.getUserEncryptKey(openid, sessionKey);
} catch (WxErrorException e) {
  if ("签名错误".equals(e.getMessage())) {
    // sessionKey missing/invalid — re-run the mini-program login flow
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling wxMaService.getInternetService().getUserEncryptKey(openid, sessionKey) with a null (or never-obtained) sessionKey. Occurs when jscode2session was never called, the session key expired before this call, or the wrong value (e.g. openid) was passed in the sessionKey slot.

Common situations: Backend skipped code2Session before requesting the encrypt key; sessionKey expired past WeChat's short TTL and was read as null from cache; deserializing a stored session that was missing; passing openid where sessionKey belongs.

Related errors


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