filterChain.doFilter后使用response對象引起的問題

1芥炭、問題出現(xiàn)的現(xiàn)象:

在舊版接口平臺產(chǎn)品中發(fā)現(xiàn)原來的計費通過過濾器實現(xiàn),在計費檢查通過后恃慧,請求發(fā)送到servlet進行處理园蝠,然后根據(jù)servlet處理結(jié)果判斷是否需要計費,如果計費失敗則拋出異常(暫不考慮計費流程設(shè)計的瑕疵糕伐,這里僅討論問題及解決方案)

public class FeesFilter extends OncePerRequestFilter {
// 之前有一些計費檢查的邏輯
    
    filterChain.doFilter(request, response);
    
// 此處進行扣費砰琢,如果費用不足向客戶端輸出錯誤響應(yīng)
    if (!consumeFeignResponse.success()) {
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getOutputStream().println(new String(JacksonUtil.toJson(responseBody).getBytes(), StandardCharsets.ISO_8859_1));
    }
}

如果代碼按照現(xiàn)有的邏輯走,會出現(xiàn)以下現(xiàn)象

{
    "code": "OK",
    "msg": "成功",
    "request_id": "1a7decfbe849ea47",
    "data": "xxxx"
}
{
    "code": "fees.INSUFFICIENT_FEES",
    "msg": "費用不足",
    "sign_type": "md5",
    "request_id": "f604fd519a7f35fc"
}

出現(xiàn)這樣問題的原因是因為在servletresponse接口中有這么一個屬性

    /**
     * Returns a boolean indicating if the response has been committed. A
     * committed response has already had its status code and headers written.
     *
     * @return a boolean indicating if the response has been committed
     * @see #setBufferSize
     * @see #getBufferSize
     * @see #flushBuffer
     * @see #reset
     */
    public boolean isCommitted();

當isCommitted=true時,響應(yīng)已經(jīng)提供給客戶端陪汽,所以無法調(diào)用reset()來重置response中的內(nèi)容训唱,再調(diào)用輸出流只會追加輸出內(nèi)容。

response.reset()挚冤;

2况增、解決方案

該方案也是摘抄自網(wǎng)絡(luò),非原創(chuàng)

問題的來源在于在filterChain中傳入的response已經(jīng)寫入了不該寫入的數(shù)據(jù)训挡,所以可以通過包裝類澳骤,使用自定義的字節(jié)流代替原有的字節(jié)流,再根據(jù)邏輯判斷該輸出包裝類里面的字節(jié)流還是另輸出異常信息澜薄。

// 之前過濾鏈可以修改成這樣
ResponseWrapper responseWrapper = new ResponseWrapper(response);
filterChain.doFilter(request, responseWrapper);

// 如果計費失敗使用response輸出異常信息
response.setCharacterEncoding("UTF-8");
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getOutputStream().println(new String(JacksonUtil.toJson(responseBody).getBytes(), StandardCharsets.ISO_8859_1));

// 如果計費成功为肮,輸出包裝類里的接口數(shù)據(jù)
response.getOutputStream().write(responseWrapper.getBuffer());

public class ResponseWrapper extends HttpServletResponseWrapper {
    private final HttpServletResponse response;
    private final ByteArrayOutputStream bout = new ByteArrayOutputStream();// 字節(jié)流
    public ResponseWrapper(HttpServletResponse response) {
        super(response);
        this.response = response;
    }
    
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ResponseWrapperServletOutputStream(bout);
    }

    public byte[] getBuffer() {
        try {
            if (pw != null) {
                // 如果pw不為空,則我們需要關(guān)閉一下肤京,讓其將數(shù)據(jù)從緩存寫到底層流中去
                pw.close();
            }
            bout.flush();
            return bout.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

class ResponseWrapperServletOutputStream extends ServletOutputStream {

    private final ByteArrayOutputStream bout;

    public ResponseWrapperServletOutputStream(ByteArrayOutputStream bout) {
        this.bout = bout;
    }
    @Override
    public void write(int arg0) throws IOException {
        this.bout.write(arg0);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颊艳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子忘分,更是在濱河造成了極大的恐慌棋枕,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妒峦,死亡現(xiàn)場離奇詭異重斑,居然都是意外死亡,警方通過查閱死者的電腦和手機肯骇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門窥浪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人笛丙,你說我怎么就攤上這事寒矿。” “怎么了若债?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵符相,是天一觀的道長。 經(jīng)常有香客問我蠢琳,道長啊终,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任傲须,我火速辦了婚禮蓝牲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泰讽。我一直安慰自己例衍,他們只是感情好昔期,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著佛玄,像睡著了一般硼一。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梦抢,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天般贼,我揣著相機與錄音,去河邊找鬼奥吩。 笑死哼蛆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的霞赫。 我是一名探鬼主播腮介,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼端衰!你這毒婦竟也來了萤厅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤靴迫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后楼誓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玉锌,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年疟羹,在試婚紗的時候發(fā)現(xiàn)自己被綠了主守。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡榄融,死狀恐怖参淫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情愧杯,我是刑警寧澤涎才,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站力九,受9級特大地震影響耍铜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跌前,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一棕兼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抵乓,春花似錦伴挚、人聲如沸靶衍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颅眶。三九已至,卻和暖如春败徊,著一層夾襖步出監(jiān)牢的瞬間帚呼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工皱蹦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煤杀,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓沪哺,卻偏偏與公主長得像沈自,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辜妓,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

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

  • 從三月份找實習到現(xiàn)在枯途,面了一些公司,掛了不少籍滴,但最終還是拿到小米酪夷、百度、阿里孽惰、京東晚岭、新浪、CVTE勋功、樂視家的研發(fā)崗...
    時芥藍閱讀 42,213評論 11 349
  • JVM 說一下 jvm 的主要組成部分坦报?及其作用? JVM包括類加載子系統(tǒng)狂鞋、堆片择、方法區(qū)、棧骚揍、本地方法棧字管、程序計數(shù)器...
    文刀雨木同閱讀 426評論 0 1
  • 一、簡介 (1) web服務(wù)器收到客戶端的http請求信不,會針對每一次請求纤掸,分別創(chuàng)建一個用于代表請求的request...
    yjaal閱讀 1,638評論 2 9
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)浑塞,斷路器借跪,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 該筆記來源于 黑馬傳智2020最新 以及 傳智Javaweb ,此筆記是我將兩者的綜合而成 請求響應(yīng)流程圖: re...
    Yan1001閱讀 306評論 0 0