最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java如何解決發(fā)送Post請求報Stream?closed問題

 更新時間:2022年06月13日 09:07:01   作者:胡安民  
這篇文章主要介紹了Java如何解決發(fā)送Post請求報Stream?closed問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

springboot項目還是ssm等java常用框架都會有這樣的問題,解決辦法通用

問題場景

前端發(fā)送Post請求,前端返回400 Bad Request,后端Controller層接口也沒進去,然后我就開始分析,是啥問題,我通過后端控制臺發(fā)現(xiàn)HttpMessageNotReadableException 提示信息,這個不是讀取請求的消息錯誤發(fā)生的異常嗎?

然后我通過IDEA 的DEBUG攔截這個異常發(fā)生的位置,然后將相關(guān)的代碼從新走了一遍發(fā)現(xiàn)在

AbstractMessageConverterMethodArgumentResolver->readWithMessageConverters

EmptyBodyCheckingHttpInputMessage 是內(nèi)部類

控制臺打印warn 信息如下:

org.springframework.http.converter.HttpMessageNotReadableException:  I/O error while reading input message; nested exception is java.io.IOException: Stream closed

問題分析

這是因為有人在過濾器或者攔截器中對Request的請求體中的數(shù)據(jù)流讀取了一遍導致的,Springboot準備讀取Body數(shù)據(jù)映射到接口的實體類參數(shù)時候失敗,發(fā)現(xiàn)流已經(jīng)沒有內(nèi)容了,因為在接口數(shù)據(jù)流傳輸使用的都是InputStream 這個流只能被讀取一次

解決辦法

將InputStream 傳輸數(shù)據(jù),緩存起來,保存到字符串中,之后用的時候?qū)⒆址D(zhuǎn)在轉(zhuǎn)換為流,那么這個字符串就能持續(xù)的被復用了

緩存數(shù)據(jù)

package com.schemautils;
/**
 * 解決獲取post請求的請求體body只能讀取一次問題
 */
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class RequestWrapper extends HttpServletRequestWrapper {
    private final String body;
    public RequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
         //防止未初始化body,我們手動初始化body ,內(nèi)部會將body內(nèi)容初始化到InputStream里
	        request.getParameterMap();
	        //然后在讀取InputStream
	       inputStream = request.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            } else {
                stringBuilder.append("");
            }
        } catch (IOException ex) {
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        body = stringBuilder.toString();
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletInputStream = 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 byteArrayInputStream.read();
            }
        };
        return servletInputStream;
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
    public JSONObject getBody() {
        return JSONObject.parseObject(this.body);
    }
}

添加過濾器并且配置緩存類

package com.schemautils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
//獲取請求中的流,將取出來的,再次轉(zhuǎn)換成流,然后把它放入到新request對象中
//必須保證在所有過濾器之前執(zhí)行,否則就會出現(xiàn)問題(按照首字母進行過濾器優(yōu)先級A>B>C)
@WebFilter(filterName = "ACacheHttpServletRequestFilter", urlPatterns = "/")
public class CacheHttpServletRequestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
        }
        //獲取請求中的流如何,將取出來的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request對象中
        // 在chain.doFiler方法中傳遞新的request對象
        if(null == requestWrapper) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }
    @Override
    public void destroy() {
    }
}

在啟動類上開啟掃描Filter注解

@SpringBootApplication(scanBasePackages = "com")
@ServletComponentScan //開啟掃描Filter
public class ApplicatioBoot {
    public static void main(String[] args) {
        SpringApplication.run(ApplicatioBoot.class,args);
    }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring MVC @GetMapping和@PostMapping注解的使用方式

    Spring MVC @GetMapping和@PostMapping注解的使用方式

    這篇文章主要介紹了Spring MVC @GetMapping和@PostMapping注解的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot返回文件使前端下載的幾種方式小結(jié)

    SpringBoot返回文件使前端下載的幾種方式小結(jié)

    本文主要介紹了Spring Boot中幾種文件下載的方法,通過后端應(yīng)用下載文件并進行業(yè)務(wù)處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-11-11
  • Java 如何在switch case語句中聲明變量

    Java 如何在switch case語句中聲明變量

    這篇文章主要介紹了Java 如何在switch case語句中聲明變量,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • ElasticSearch的安裝與基本概念

    ElasticSearch的安裝與基本概念

    這篇文章主要介紹了ElasticSearch的安裝與基本概念,提供了一個分布式多用戶能力的全文搜索引擎,Elasticsearch是用Java開發(fā)的,需要的朋友可以參考下
    2023-04-04
  • 淺談java web中常用對象對應(yīng)的實例化接口

    淺談java web中常用對象對應(yīng)的實例化接口

    下面小編就為大家?guī)硪黄獪\談java web中常用對象對應(yīng)的實例化接口。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 談?wù)刯ava的concurrent用法

    談?wù)刯ava的concurrent用法

    這篇文章給大家介紹java的concurrent用法,感興趣的朋友一起學習吧
    2015-10-10
  • SpringBoot+Redis執(zhí)行l(wèi)ua腳本的方法步驟

    SpringBoot+Redis執(zhí)行l(wèi)ua腳本的方法步驟

    這篇文章主要介紹了SpringBoot+Redis執(zhí)行l(wèi)ua腳本的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • 詳解如何使用Mybatis的攔截器

    詳解如何使用Mybatis的攔截器

    MyBatis?攔截器是?MyBatis?提供的一個強大特性,它允許你在?MyBatis?執(zhí)行其核心邏輯的關(guān)鍵節(jié)點插入自定義邏輯,從而改變?MyBatis?的默認行為,本文給大家詳細介紹了如何使用Mybatis的攔截器,需要的朋友可以參考下
    2024-03-03
  • Java8新特性之Collectors.joining()實例詳解

    Java8新特性之Collectors.joining()實例詳解

    在項目中我們常常要對list集合的數(shù)據(jù)做一些字符串拼接/處理等相關(guān)操作,下面這篇文章主要給大家介紹了關(guān)于Java8新特性之Collectors.joining()的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • SpringBoot在IDEA中實現(xiàn)熱部署(JRebel實用版)

    SpringBoot在IDEA中實現(xiàn)熱部署(JRebel實用版)

    這篇文章主要介紹了SpringBoot在IDEA中實現(xiàn)熱部署(JRebel實用版),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05

最新評論

曲阜市| 绥阳县| 泰和县| 大化| 河西区| 武安市| 乌拉特前旗| 新昌县| 宣化县| 张家港市| 文昌市| 舟山市| 五大连池市| 诸暨市| 峨山| 绥宁县| 三都| 新邵县| 称多县| 伊川县| 临洮县| 邹平县| 会东县| 建平县| 兴山县| 日喀则市| 莱阳市| 宁南县| 大丰市| 揭西县| 长春市| 兴国县| 凌云县| 佛学| 垦利县| 婺源县| 延津县| 临夏市| 米林县| 咸阳市| 甘南县|