【微信支付回調(diào)】踩過坑

場景,接手項目負責維護,交接中未明確提及項目是否跑通過微信支付成功回調(diào)。
后臺能正常接受到微信的傳參:

#微信官方回調(diào)參數(shù)
<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>

那么就只要模擬微信回調(diào)不就可以了嘛,網(wǎng)上找到以下方法...
通過POSTMAN請求命中自己的回調(diào)接口
POST http://127.0.0.1:8888/wx/payNotify
上訴微信返回數(shù)據(jù)放于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.微信能夠回調(diào),且APP能夠正常支付锋爪,客戶端是沒有問題的丙曙。
2.支付回調(diào)給我的參數(shù)是對的,所有只有解析的時候是有問題的其骄。

所以和同事打算從新找一遍排查問題:重新弄的下單流程亏镰,梳理邏輯為:傳參,傳參生成簽名拯爽,一起傳那預(yù)支付訂單索抓,及再次簽名傳APP,支付成功,得到微信回調(diào)逼肯。這邏輯沒毛病...

開始找為什么輸入流報IO錯誤:【Stream closed】
于是開始排查是不是傳參的時候把stream處理過耸黑,導(dǎo)致后面就一直失敗,這時候感覺方向又迷茫又清晰篮幢。

看別人代碼整個頭大了...
他們的自定義攔截器寫了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: 復(fù)制輸入流</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() {
    }
}

案承!A砘肌Eβ摇!成功了昆箕,body的值獲取正常了...
之前技術(shù)看來是從來沒有接收到過微信回調(diào)的數(shù)據(jù)啊...
眼淚要下來了...我的頭發(fā)感覺都少了幾根...

再次走正常流程下單...回調(diào)成功了Q涣小!E籼取薯嗤!
交接時候我讓對方寫了是否有已知事項未處理...
什么都未告知!O吮谩B娼恪!講道理浪費時間了...

謹記捏题。
2021年3月12日18:27:32

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末玻褪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子公荧,更是在濱河造成了極大的恐慌带射,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件循狰,死亡現(xiàn)場離奇詭異窟社,居然都是意外死亡,警方通過查閱死者的電腦和手機绪钥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進店門灿里,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人程腹,你說我怎么就攤上這事钠四。” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵缀去,是天一觀的道長侣灶。 經(jīng)常有香客問我,道長缕碎,這世上最難降的妖魔是什么褥影? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮咏雌,結(jié)果婚禮上凡怎,老公的妹妹穿的比我還像新娘。我一直安慰自己赊抖,他們只是感情好统倒,可當我...
    茶點故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氛雪,像睡著了一般房匆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上报亩,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天浴鸿,我揣著相機與錄音,去河邊找鬼弦追。 笑死岳链,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的劲件。 我是一名探鬼主播掸哑,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼零远!你這毒婦竟也來了举户?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤遍烦,失蹤者是張志新(化名)和其女友劉穎俭嘁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體服猪,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨居荒郊野嶺守林人離奇死亡供填,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了罢猪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片近她。...
    茶點故事閱讀 40,973評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膳帕,靈堂內(nèi)的尸體忽然破棺而出粘捎,到底是詐尸還是另有隱情薇缅,我是刑警寧澤,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布攒磨,位于F島的核電站泳桦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娩缰。R本人自食惡果不足惜灸撰,卻給世界環(huán)境...
    茶點故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拼坎。 院中可真熱鬧浮毯,春花似錦、人聲如沸泰鸡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盛龄。三九已至饰迹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讯嫂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工兆沙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欧芽,地道東北人。 一個月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓葛圃,卻偏偏與公主長得像千扔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子库正,可洞房花燭夜當晚...
    茶點故事閱讀 45,982評論 2 361

推薦閱讀更多精彩內(nèi)容