close
The Wayback Machine - https://web.archive.org/web/20201106124038/https://github.com/Wechat-Group/WxJava/issues/1087
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

长链接转短链接接口的小BUG #1087

Closed
sinrimin opened this issue Jun 25, 2019 · 3 comments
Closed

长链接转短链接接口的小BUG #1087

sinrimin opened this issue Jun 25, 2019 · 3 comments
Labels
bug

Comments

@sinrimin
Copy link

@sinrimin sinrimin commented Jun 25, 2019

准确来说应该是微信接口的BUG,但可能会在一定条件下瞬间刷爆access_token。

简要描述

长链接转短链接接口中的 long_url 如果带有名为 access_token 的参数,会直接导致接口返回 40001,如果项目的 autoRefreshToken 也正好是 true ,会直接导致 java.lang.StackOverflowError 并刷爆服务号的 access_token

模块版本情况

  • WxJava 模块名: weixin-java-mp
  • WxJava 版本号:3.3.0

期待结果 和 实际情况

先说说微信的BUG

使用官方例子调用长链接转短链接( long_url 添加 access_token 参数):

 curl -d "{\"action\":\"long2short\",\"long_url\":\"http://wap.koudaitong.com/v2/showcase/goods?alias=128wi9shh&spm=h56083&redirect_count=1&access_token={random_str}\"}" "https://api.weixin.qq.com/cgi-bin/shorturl?access_token={access_token}"
  • {random_str} : 随机字符串,网址中的参数名正好被命名成了access_token
  • {access_token} : 正常可用的微信access_token

返回值

{"errcode":40001,"errmsg":"invalid credential, access_token is invalid or not latest hint: [1l1fVa08158619!]"}

修改上面long_url中 access_token 的参数名,或者去掉 access_token 这个参数(这里改成了 bccess_token

 curl -d "{\"action\":\"long2short\",\"long_url\":\"http://wap.koudaitong.com/v2/showcase/goods?alias=128wi9shh&spm=h56083&redirect_count=1&bccess_token={random_str}\"}" "https://api.weixin.qq.com/cgi-bin/shorturl?access_token={access_token}"
  • {random_str} : 同上
  • {access_token} : 同上

返回值

{"errcode":0,"errmsg":"ok","short_url":"https:\/\/w.url.cn\/s\/AdCvL5R"}

再看看项目中的代码

me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl

  ...
  public <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
      ...
      if (error.getErrorCode() == 42001 || error.getErrorCode() == 40001 || error.getErrorCode() == 40014) {
        this.getWxMpConfigStorage().expireAccessToken();
        if (this.getWxMpConfigStorage().autoRefreshToken()) {
          return this.execute(executor, uri, data);
        }
      }
  ...

代码中判断到 40001 会让当前 access_token 失效,并且判断到 autoRefreshToken 会继续调用 this.execute()方法

  public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
  ...
      try {
        return this.executeInternal(executor, uri, data);
      } catch (WxErrorException e) {
  ...

也就是回到上一个方法,但同样会返回 40001,开始死循环。

日志

Handler dispatch failed; nested exception is java.lang.StackOverflowError
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:982)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Caused by: java.lang.StackOverflowError: null
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
	at sun.security.ssl.InputRecord.read(InputRecord.java:503)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
	at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:930)
	at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
	at okio.Okio$2.read(Okio.java:139)
@binarywang
Copy link
Member

@binarywang binarywang commented Jul 9, 2019

这确实挺坑爹的

@sinrimin
Copy link
Author

@sinrimin sinrimin commented Jul 9, 2019

😥 要不是我这边正好刷新access_token的逻辑有些问题(中心化的,没有强刷机制),就直接线上事故了,可以考虑在接口强行过滤下,免得有人踩雷

@binarywang
Copy link
Member

@binarywang binarywang commented Aug 23, 2019

3.5.2.B 测试版本已修复,麻烦验证一下,谢谢了

@binarywang binarywang closed this Aug 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.