欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Springboot應(yīng)用中過濾器如何修改response的header和body內(nèi)容

 更新時間:2023年07月19日 10:06:08   作者:彼岸花@開  
這篇文章主要介紹了Springboot應(yīng)用中過濾器如何修改response的header和body內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Springboot過濾器修改response的header和body內(nèi)容

springboot添加過濾器,繼承Filter接口,實現(xiàn)doFilter方法

方法一,實現(xiàn)類增加注解@WebFilter,注解參數(shù)filterName表示過濾器名稱,urlPatterns表示要過濾的url路徑,在啟動類增加注解@ServletComponentScan,表示能掃描到該類。

當(dāng)有多個過濾器時,通過注解@Order,注解參數(shù)大小表示過濾器執(zhí)行的縣厚順序,越小越先執(zhí)行

@WebFilter(filterName = "responseFilter",urlPatterns = "/*")
public class ResponseFilter implements Filter

方法二,創(chuàng)建新配置類,添加 @Configuration 注解,將自定義Filter加入過濾鏈。

@Configuration
public class DefinedFilterConfig {
? ? @Bean
? ? public FilterRegistrationBean responseFilter() {
? ? ? ? FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
? ? ? ? ResponseFilter responseFilter = new ResponseFilter();
? ? ? ? filterRegistrationBean.setFilter(responseFilter);
? ? ? ? filterRegistrationBean.addUrlPatterns("/*");//配置過濾規(guī)則
? ? ? ? filterRegistrationBean.setName("responseFilter");//設(shè)置過濾器名稱
? ? ? ? filterRegistrationBean.setOrder(1);//執(zhí)行次序
? ? ? ? return filterRegistrationBean;
? ? }
}

springboot在response中添加或者修改header

分兩種情況

  • 情況1,在chain.doFilter(servletRequest, servletResponse)代碼之前
servletResponse.addHeader("XXX", "xxxx");

或者

servletResponse.setHeader("XXX", "xxxx");

兩者的區(qū)別是addHeader不會覆蓋,只會追加,會照成headerName重名

setHeader會覆蓋重名的headerName

這樣是可以添加成功

  • 情況2,在chain.doFilter(servletRequest, servletResponse)代碼之后

添加addHeader或者serHeader無效,是因為這和過濾器的處理流程以及對header的處理時機有關(guān)

首先過濾器鏈的處理流程是:進入到一個過濾器的doFitler方法中,處理一些邏輯,然后調(diào)用chain.doFilter(request, httpServletResponse);進入到過濾器鏈的下一個過濾器的doFilter方法中.當(dāng)在過濾器鏈上最后一個過濾器的doFilter方法中調(diào)用chain.doFilter(request, httpServletResponse);時,將會把請求轉(zhuǎn)發(fā)到Servlet中,再分配到對應(yīng)的Controller的方法中。當(dāng)從Controller的方法中退出,再回到最后一個過濾器的doFilter方法中之前,就將會把respone對象上的header寫入到headerBuffer中。

所以,在chain.doFilter()方法之后,一方面是給response對象設(shè)置header不會成功,因為發(fā)現(xiàn)response對象的狀態(tài)已經(jīng)是commited狀態(tài),就不會再寫入到headers里,另一方面,即便通過反射的方式寫入了,也不會輸出給客戶端,因為headers已經(jīng)處理過了。

springboot在response中修改body

spring提供了HttpServletResponse的包裝類HttpServletResponseWrapper

首先需要繼承該包裝類,生成自定義包裝類BodyCachingHttpServletResponseWrapper

public class BodyCachingHttpServletResponseWrapper extends HttpServletResponseWrapper {
? ? private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
? ? private HttpServletResponse response;
? ? private PrintWriter pwrite;
? ? public BodyCachingHttpServletResponseWrapper(HttpServletResponse response) {
? ? ? ? super(response);
? ? ? ? this.response = response;
? ? }
? ? public byte[] getBytes() {
? ? ? ? if(pwrite != null) {
? ? ? ? ? ? pwrite.close();
? ? ? ? ? ? return byteArrayOutputStream.toByteArray();
? ? ? ? }
? ? ? ? if(byteArrayOutputStream != null) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? byteArrayOutputStream.flush();
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return byteArrayOutputStream.toByteArray();
? ? }
? ? @Override
? ? public ServletOutputStream getOutputStream() {
? ? ? ? return new ServletOutputStreamWrapper(this.byteArrayOutputStream , this.response);
? ? }
? ? @Override
? ? public PrintWriter getWriter() throws IOException {
? ? ? ? pwrite = new PrintWriter(new OutputStreamWriter(this.byteArrayOutputStream , this.response.getCharacterEncoding()));
? ? ? ? return pwrite;
? ? }
? ? private static class ServletOutputStreamWrapper extends ServletOutputStream {
? ? ? ? private ByteArrayOutputStream outputStream;
? ? ? ? private HttpServletResponse response;
? ? ? ? public ServletOutputStreamWrapper(ByteArrayOutputStream outputStream, HttpServletResponse response) {
? ? ? ? ? ? super();
? ? ? ? ? ? this.outputStream = outputStream;
? ? ? ? ? ? this.response = response;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public boolean isReady() {
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void setWriteListener(WriteListener listener) {
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void write(int b) throws IOException {
? ? ? ? ? ? this.outputStream.write(b);
? ? ? ? }
// ? ? ? ?@Override
// ? ? ? ?public void flush() throws IOException {
// ? ? ? ? ? ?if (! this.response.isCommitted()) {
// ? ? ? ? ? ? ? ?byte[] body = this.outputStream.toByteArray();
// ? ? ? ? ? ? ? ?ServletOutputStream outputStream = this.response.getOutputStream();
// ? ? ? ? ? ? ? ?outputStream.write(body);
// ? ? ? ? ? ? ? ?outputStream.flush();
// ? ? ? ? ? ?}
// ? ? ? ?}
? ? }

然后通過過濾器,將自定義包裝類BodyCachingHttpServletResponseWrappe傳遞到chain.doFilter(servletRequest, bodyCachingHttpServletResponseWrapper ),通過bodyCachingHttpServletResponseWrapper .getBytes()方式獲得原有body的內(nèi)容。

最后自己根據(jù)自己的邏輯代碼,修改原有body的內(nèi)容,重新寫入輸出流即可

public class ResponseFilter implements Filter {
? ? @Override
? ? public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
? ? ? ? ? ? throws IOException, ServletException {
? ? ? ? BodyCachingHttpServletResponseWrapper responseWrapper = new BodyCachingHttpServletResponseWrapper((HttpServletResponse) servletResponse);
? ? ? ? //獲取當(dāng)前accessToken
? ? ? ? Optional<String> currentUserAccessTokenOptional = SecurityUtils.getCurrentUserAccessToken();
? ? ? ? String currentUserAccessToken = null;
? ? ? ? if(currentUserAccessTokenOptional.isPresent()) {
? ? ? ? ? ? currentUserAccessToken = currentUserAccessTokenOptional.get();
? ? ? ? }
? ? ? ? responseWrapper.addHeader("xuncai_access_token", currentUserAccessToken);
? ? ? ? chain.doFilter(servletRequest, responseWrapper);
? ? ? ? Optional<String> xTotalCount = Optional.ofNullable(responseWrapper.getHeader("X-Total-Count"));
? ? ? ? byte[] writeValueByte = null;
? ? ? ? if(xTotalCount.isPresent() && responseWrapper.getBytes() != null) {
? ? ? ? ? ? String currentTotal = xTotalCount.get();
? ? ? ? ? ? String currentData = new String(responseWrapper.getBytes());
? ? ? ? ? ? String writeValue = "{\"total\":"+currentTotal+",\"data\":"+currentData+"}";
? ? ? ? ? ? writeValueByte = writeValue.getBytes();
? ? ? ? }else {
? ? ? ? ? ? writeValueByte = responseWrapper.getBytes();
? ? ? ? }
? ? ? ? //重新寫入輸出流
? ? ? ? ServletOutputStream outputStream = servletResponse.getOutputStream();
? ? ? ? outputStream.write(writeValueByte);
? ? ? ? outputStream.flush();
? ? ? ? outputStream.close();
? ? }
}

經(jīng)過測試,一切OK。

Springboot在絕大部分過濾器中修改請求頭信息

實現(xiàn)方式

反射。

代碼

package one.util;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;
import org.springframework.util.ObjectUtils;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class HeadersEdit {
    private final HttpServletRequest request;
    private Map<String, String> modifyHeaders;
    private MimeHeaders itsHeaders;
    private boolean isDeleteKnown=true;
    public HeadersEdit(HttpServletRequest request){
        this.request=request;
        modifyHeaders= new HashMap<>();
        itsHeaders=getMimeHeaders(getRequestFacade());
    }
    private HttpServletRequest getRequestFacade(){
        try{
            Field field= ServletRequestWrapper.class.getDeclaredField("request");
            HttpServletRequest result;
            field.setAccessible(true);
            result=(HttpServletRequest)field.get((request));
            while(!(result instanceof RequestFacade)){
                result=(HttpServletRequest)field.get((result));
            }
            return result;
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("HeadersEdit Error!");
        }
    }
    private MimeHeaders getMimeHeaders(HttpServletRequest requestFacade){
        try{
            Field itsRequest= RequestFacade.class.getDeclaredField("request");
            itsRequest.setAccessible(true);
            HttpServletRequest o5=(HttpServletRequest) itsRequest.get(requestFacade);
            Field coyoteField= Request.class.getDeclaredField("coyoteRequest");
            coyoteField.setAccessible(true);
            org.apache.coyote.Request coyoteRequest=(org.apache.coyote.Request) coyoteField.get(o5);
            Field headers=org.apache.coyote.Request.class.getDeclaredField("headers");
            headers.setAccessible(true);
            return (MimeHeaders)headers.get(coyoteRequest);
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("HeadersEdit Error!");
        }
    }
    private boolean setValueExecutor(Map<String,String>newHeaders){
        String key;
        for(Map.Entry<String, String> entry : newHeaders.entrySet()){
            key=entry.getKey();
            if(itsHeaders.getHeader(key)!=null){
                if(isDeleteKnown){
                    itsHeaders.removeHeader(key);
                }else{
                    return false;
                }
            }
            itsHeaders.addValue(key).setString(entry.getValue());
        }
        return true;
    }
    public boolean setValue(String key,String value){
        if(ObjectUtils.isEmpty(key)||ObjectUtils.isEmpty(value)){
            return false;
        }
        Map<String,String>map=new HashMap<>();
        map.put(key,value);
        return setValueExecutor(map);
    }
    public boolean setValue(Map<String,String>newHeaders){
        if(ObjectUtils.isEmpty(newHeaders)){
            return false;
        }
        return setValueExecutor(newHeaders);
    }
    public void changeCheck(){
        isDeleteKnown=!isDeleteKnown;
    }
}

測試環(huán)境

springsecurity中的過濾器、以及普通的過濾器。

原理簡述

許多過濾器都間接繼承了ServletRequestWrapper類,它有個屬性叫request。

springsecurity或者普通的過濾器類只是將其包裝了多層,通過反射一層一層剝開即可。

總結(jié)

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

相關(guān)文章

  • SpringBoot整合Redis實現(xiàn)token緩存

    SpringBoot整合Redis實現(xiàn)token緩存

    于token通常會被多次使用,我們需要把它保存到緩存中,以減少頻繁地訪問數(shù)據(jù)庫,本文主要介紹了SpringBoot整合Redis實現(xiàn)token緩存,感興趣的可以了解一下
    2024-02-02
  • Java使用Instant時輸出的時間比預(yù)期少了八個小時

    Java使用Instant時輸出的時間比預(yù)期少了八個小時

    在Java中,LocalDateTime表示沒有時區(qū)信息的日期和時間,而Instant表示基于UTC的時間點,本文主要介紹了Java使用Instant時輸出的時間比預(yù)期少了八個小時的問題解決,感興趣的可以了解一下
    2024-09-09
  • 創(chuàng)建一個Java的不可變對象

    創(chuàng)建一個Java的不可變對象

    這篇文章主要介紹了創(chuàng)建一個Java的不可變對象,一個類的對象在通過構(gòu)造方法創(chuàng)建后如果狀態(tài)不會再被改變,那么它就是一個不可變(immutable)類。它的所有成員變量的賦值僅在構(gòu)造方法中完成,不會提供任何 setter 方法供外部類去修改,需要的朋友可以參考下
    2021-11-11
  • Spring boot項目中異常攔截設(shè)計和處理詳解

    Spring boot項目中異常攔截設(shè)計和處理詳解

    這篇文章主要介給大家紹了關(guān)于Spring boot項目中異常攔截設(shè)計和處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2018-12-12
  • spring boot補習(xí)系列之幾種scope詳解

    spring boot補習(xí)系列之幾種scope詳解

    這篇文章主要給大家介紹了關(guān)于spring boot補習(xí)系列之幾種scope的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • futuretask源碼分析(推薦)

    futuretask源碼分析(推薦)

    這篇文章主要介紹了futuretask源碼分析(推薦),小編覺得還是挺不錯的,這里給大家分享下,供各位參考。
    2017-10-10
  • java中static關(guān)鍵字用法詳解

    java中static關(guān)鍵字用法詳解

    這篇文章主要為大家詳細介紹了java中static關(guān)鍵字的用法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • SpringBoot實現(xiàn)網(wǎng)頁消息推送的5種方法小結(jié)

    SpringBoot實現(xiàn)網(wǎng)頁消息推送的5種方法小結(jié)

    項目開發(fā)中,實時消息推送已成為提升用戶體驗的關(guān)鍵技術(shù),本文將詳細介紹SpringBoot中實現(xiàn)網(wǎng)頁消息推送的幾種主流方案,希望對大家有所幫助
    2025-03-03
  • 詳解@Autowired是如何注入變量的

    詳解@Autowired是如何注入變量的

    在?Spring?容器中,當(dāng)我們想給某一個屬性注入值的時候,有多種不同的方式,例如使用?@Autowired、@Inject等注解,下面小編就來和小伙伴們聊一聊,@Autowired?到底是如何把數(shù)據(jù)注入進來的
    2023-07-07
  • SpringBoot實現(xiàn)websocket服務(wù)端及客戶端的詳細過程

    SpringBoot實現(xiàn)websocket服務(wù)端及客戶端的詳細過程

    文章介紹了WebSocket通信過程、服務(wù)端和客戶端的實現(xiàn),以及可能遇到的問題及解決方案,感興趣的朋友一起看看吧
    2024-12-12

最新評論