美文网首页
【微信支付回调】踩过坑

【微信支付回调】踩过坑

作者: 吕吕吕丶 | 来源:发表于2021-03-12 18:27 被阅读0次

    场景,接手项目负责维护,交接中未明确提及项目是否跑通过微信支付成功回调。
    后台能正常接受到微信的传参:

    #微信官方回调参数
    <xml>
      <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
      <attach><![CDATA[支付测试]]></attach>
      <bank_type><![CDATA[CFT]]></bank_type>
      <fee_type><![CDATA[CNY]]></fee_type>
      <is_subscribe><![CDATA[Y]]></is_subscribe>
      <mch_id><![CDATA[10000100]]></mch_id>
      <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
      <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
      <out_trade_no><![CDATA[1409811653]]></out_trade_no>
      <result_code><![CDATA[SUCCESS]]></result_code>
      <return_code><![CDATA[SUCCESS]]></return_code>
      <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
      <time_end><![CDATA[20140903131540]]></time_end>
      <total_fee>1</total_fee>
      <coupon_fee><![CDATA[10]]></coupon_fee>
      <coupon_count><![CDATA[1]]></coupon_count>
      <coupon_type><![CDATA[CASH]]></coupon_type>
      <coupon_id><![CDATA[10000]]></coupon_id>
      <trade_type><![CDATA[JSAPI]]></trade_type>
      <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
    </xml>
    

    那么就只要模拟微信回调不就可以了嘛,网上找到以下方法...
    通过POSTMAN请求命中自己的回调接口
    POST http://127.0.0.1:8888/wx/payNotify
    上诉微信返回数据放于Body的raw中。

    命中断点后直接报错
    java.io.IOException: Stream closed
    代码打到了有错误的第5行:

    1            InputStream inStream = request.getInputStream();
    2            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    3            byte[] buffer = new byte[1024];
    4            int len = 0;
    5            while ((len = inStream.read(buffer)) != -1) {
    6                outSteam.write(buffer, 0, len);
    7            }
    

    来回捣鼓最初想法是:
    1.微信能够回调,且APP能够正常支付,客户端是没有问题的。
    2.支付回调给我的参数是对的,所有只有解析的时候是有问题的。

    所以和同事打算从新找一遍排查问题:重新弄的下单流程,梳理逻辑为:传参,传参生成签名,一起传那预支付订单,及再次签名传APP,支付成功,得到微信回调。这逻辑没毛病...

    开始找为什么输入流报IO错误:【Stream closed】
    于是开始排查是不是传参的时候把stream处理过,导致后面就一直失败,这时候感觉方向又迷茫又清晰。

    看别人代码整个头大了...
    他们的自定义拦截器写了4个拦截配置,我该从哪里入手?

        /**
         * 添加拦截器链配置
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(AInterceptor)
                    .addPathPatterns(AInclude)
                    .excludePathPatterns(AExclude);
    
            registry.addInterceptor(BInterceptor)
                    .addPathPatterns(BInclude)
                    .excludePathPatterns(BExclude);
    
            registry.addInterceptor(CInterceptor)
                    .addPathPatterns(CInclude)
                    .excludePathPatterns(CExclude);
    
            registry.addInterceptor(DInterceptor)
                    .addPathPatterns(DInclude)
                    .excludePathPatterns(DExclude);
        }
    

    啊这?拦截我难道要每个改过去?难道我不是就只要我的body中的值不丢不就可以了么?
    那我反着把这个body的值能正常获取吧...

    那我反手把代码又加了一下

    package com.interceptor;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.ServletRequest;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.*;
    import java.nio.charset.Charset;
    
    /**
     * @author lvlvlv
     * @Description:
     * @Date:2021/1/8
     */
    public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
        public byte[] body;
    
        public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
            super(request);
            body = toByteArray(request.getInputStream());
            if (ToolUtil.isEmpty(request.getInputStream())) {
                String sessionStream = getBodyString(request);
                body = sessionStream.getBytes(Charset.forName("UTF-8"));
            }
        }
    
        /**
         * 获取请求Body
         *
         * @param request
         * @return
         */
        public String getBodyString(final ServletRequest request) {
            StringBuilder sb = new StringBuilder();
            InputStream inputStream = null;
            BufferedReader reader = null;
            try {
                inputStream = cloneInputStream(request.getInputStream());
                reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
                String line = "";
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return sb.toString();
        }
    
        /**
         * Description: 复制输入流</br>
         *
         * @param inputStream
         * @return</br>
         */
        public InputStream cloneInputStream(ServletInputStream inputStream) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            try {
                while ((len = inputStream.read(buffer)) > -1) {
                    byteArrayOutputStream.write(buffer, 0, len);
                }
                byteArrayOutputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
            InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            return byteArrayInputStream;
        }
    
        private byte[] toByteArray(InputStream in) throws IOException {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024 * 4];
            int n = 0;
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream bais = new ByteArrayInputStream(body);
            return new ServletInputStream() {
                @Override
                public boolean isFinished() {
                    return false;
                }
    
                @Override
                public boolean isReady() {
                    return false;
                }
    
                @Override
                public void setReadListener(ReadListener readListener) {
    
                }
    
                @Override
                public int read() throws IOException {
                    return bais.read();
                }
            };
        }
    }
    
    

    在加一个corsFilter

    package com.interceptor;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @author bobo
     * @description:
     * @date 2019-05-26
     */
    @Component
    @WebFilter(urlPatterns = "/*", filterName = "CorsFilter")
    public class CorsFilter implements Filter {
    
        private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws 
    IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            HttpServletRequest reqs = (HttpServletRequest) req;
            String curOrigin = reqs.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", curOrigin == null ? "true" : curOrigin);
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "*");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Access-Control-Expose-Headers", "*");
            String a = reqs.getRequestURI();
            ServletRequest requestWrapper = null;
            if (req instanceof HttpServletRequest) {
                requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) req);
            }
            if (requestWrapper == null) {
                chain.doFilter(req, res);
                return;
            } else {
                chain.doFilter(requestWrapper, res);
                return;
            }
        }
    
        @Override
        public void init(FilterConfig filterConfig) {
            logger.info("========================Cors Filter Apply===============================");
        }
    
        @Override
        public void destroy() {
        }
    }
    
    

    啊!!!!成功了,body的值获取正常了...
    之前技术看来是从来没有接收到过微信回调的数据啊...
    眼泪要下来了...我的头发感觉都少了几根...

    再次走正常流程下单...回调成功了!!!!
    交接时候我让对方写了是否有已知事项未处理...
    什么都未告知!!!!讲道理浪费时间了...

    谨记。
    2021年3月12日18:27:32

    相关文章

      网友评论

          本文标题:【微信支付回调】踩过坑

          本文链接:https://www.haomeiwen.com/subject/mebzqltx.html