【微信支付回调】踩过坑

2021-03-12  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读