国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題

這篇具有很好參考價值的文章主要介紹了【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

背景

這個情況出現(xiàn)在,我需要進(jìn)行驗(yàn)證碼的校驗(yàn),因此用戶的請求首先需要被驗(yàn)證碼過濾器校驗(yàn),而驗(yàn)證碼過濾器不需要設(shè)定為全局過濾器,因此我就單純的把它設(shè)定為了一個局部過濾器,代碼如下

@Component
public class ValidateCodeFilter //implements GlobalFilter, Ordered
        extends AbstractGatewayFilterFactory<Object>
{
    //需要生成驗(yàn)證碼的路徑
    private final static String[] VALIDATE_URL =
            new String[] { "/auth/login", "/auth/register" };
    //驗(yàn)證碼服務(wù)
    @Autowired
    private ValidateCodeService validateCodeService;
    //驗(yàn)證碼配置學(xué)習(xí)
    @Autowired
    private CaptchaProperties captchaProperties;
    //驗(yàn)證碼內(nèi)容
    private static final String CODE = "code";
    //驗(yàn)證碼的uuid
    private static final String UUID = "uuid";

    @Override
    public GatewayFilter apply(Object config)
    {
         return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            // 非登錄/注冊請求或驗(yàn)證碼關(guān)閉,不處理
            if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(),
                    VALIDATE_URL) || !captchaProperties.getEnabled())
            {
                return chain.filter(exchange);
            }

            try
            {
                String rspStr = resolveBodyFromRequest(request);
                //接收J(rèn)SON格式的請求
                JSONObject obj = JSON.parseObject(rspStr);
                validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
            }
            catch (Exception e)
            {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
            }
            return chain.filter(exchange);
        };
    }

    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
    {
        // 獲取請求體
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }
}

然后我進(jìn)行請求的時候,json參數(shù)如下
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
然后請求經(jīng)過解析后會發(fā)現(xiàn),字符串居然是null
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
具體原因不太確定,但是應(yīng)該是網(wǎng)絡(luò)傳遞的時候,這個數(shù)據(jù)丟失了,原本的數(shù)據(jù)應(yīng)該封裝在這里
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
然后我就想著,有沒有可能是這個局部過濾器的位置的問題,因?yàn)槲抑熬褪怯捎谶@個局部過濾器的位置,放在的位置比較靠后,導(dǎo)致他壓根沒有被執(zhí)行。
例如這是我早期的配置,可以發(fā)現(xiàn),請求的路徑是重復(fù)處理的,那么就會導(dǎo)致之前的過濾器處理完畢之后,這個驗(yàn)證碼的過濾器壓根就不會被執(zhí)行,所以我就試著把這個過濾器的位置放在了更前面,方法確實(shí)得到了執(zhí)行。但是這樣子并不能解決說ServerHttpRequest的getBody返回null的問題。
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
這是在我沒有修改過濾器為之前的執(zhí)行流程,后面我修改了代碼。
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
我也明白為什么會導(dǎo)致null,其實(shí)原因是因?yàn)?br> request.getInputStream(); request.getReader(); 和request.getParameter(“key”)這三個方法中的任何一個方法執(zhí)行之后,之后再次執(zhí)行,就會失效。
所以我就想著,我應(yīng)該可以考慮重寫一下過濾器的流程,把傳遞過來的ServerHttpRequest進(jìn)行修改,然后重載其getBody方法,讓其去緩存中獲取數(shù)據(jù),而網(wǎng)絡(luò)上其實(shí)已經(jīng)有很多解決方式了
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
所以其實(shí)我只要能做一個緩存,讓之后的ServerHttpRequest去這個緩存中獲取數(shù)據(jù)就好。
代碼如下

package com.towelove.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * @author: Blossom
 * CacheBodyGlobalFilterk的作用是為了解決
 * ServerHttpRequest中body的數(shù)據(jù)為NULL的情況
 */
@Slf4j
@Component
public class CacheBodyGlobalFilter implements Ordered, GlobalFilter {


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (exchange.getRequest().getHeaders().getContentType() == null) {
            return chain.filter(exchange);
        } else {
            //獲取databuffer
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> { //設(shè)定返回值并處理
                        DataBufferUtils.retain(dataBuffer); //設(shè)定存儲空間
                        Flux<DataBuffer> cachedFlux = Flux//讀取Flux中所有數(shù)據(jù)并且保存
                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator( //得到ServerHttpRequest
                                exchange.getRequest()) {
                            @Override //重載getBody方法 讓其從我設(shè)定的緩存獲取
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        //放行 并且設(shè)定exchange為我重載后的
                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });
        }
    }
	    //盡可能早的對這個請求進(jìn)行封裝
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

}

CacheBodyGlobalFilter這個全局過濾器的目的就是把原有的request請求中的body內(nèi)容讀出來,并且使用ServerHttpRequestDecorator這個請求裝飾器對request進(jìn)行包裝,重寫getBody方法,并把包裝后的請求放到過濾器鏈中傳遞下去。這樣后面的過濾器中再使用exchange.getRequest().getBody()來獲取body時,實(shí)際上就是調(diào)用的重載后的getBody方法,獲取的最先已經(jīng)緩存了的body數(shù)據(jù)。這樣就能夠?qū)崿F(xiàn)body的多次讀取了。
值得一提的是,這個過濾器的order設(shè)置的是Ordered.HIGHEST_PRECEDENCE,即最高優(yōu)先級的過濾器。優(yōu)先級設(shè)置這么高的原因是某些系統(tǒng)內(nèi)置的過濾器可能也會去讀body,這樣就會導(dǎo)致我們自定義過濾器中獲取body的時候報(bào)body只能讀取一次這樣的錯誤如下:

java.lang.IllegalStateException: Only one connection receive subscriber allowed.
	at reactor.ipc.netty.channel.FluxReceive.startReceiver(FluxReceive.java:279)
	at reactor.ipc.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:129)

之后,只要讓我們后面的請求去這個緩存中獲取數(shù)據(jù)即可。增加全局過濾器之后的過濾器鏈如下。
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
之后再次發(fā)送請求,就可以發(fā)現(xiàn)我能拿到數(shù)據(jù)了,因?yàn)槠鋑etBody是從CacheBodyGlobalFilter這里獲取的數(shù)據(jù),所以當(dāng)你的請求再次執(zhí)行g(shù)etBody的時候,他會去這個類中執(zhí)行g(shù)etBody方法,所以我在debug的時候,他會再次的執(zhí)行g(shù)etBody方法
【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題
然后下面是我獲取body中數(shù)據(jù)并且進(jìn)行解析為字符串的方法

  private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
    {
        // 獲取請求體
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }

到此為止,這個問題大概是結(jié)束了。文章來源地址http://www.zghlxwxcb.cn/news/detail-487169.html

到了這里,關(guān)于【Java】SpringCloud Gateway自定義過濾器中獲取ServerHttpRequest的body中的數(shù)據(jù)為NULL的問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān),Route路由,Predicate 謂詞/斷言,F(xiàn)ilter 過濾器(十三)

    SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān),Route路由,Predicate 謂詞/斷言,F(xiàn)ilter 過濾器(十三)

    閱讀本文前可先參考 ??????SpringCloud - Spring Cloud根/父項(xiàng)目,開發(fā)準(zhǔn)備(二)_MinggeQingchun的博客-CSDN博客 SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān)(十三)_MinggeQingchun的博客-CSDN博客 Web 有三大組件(監(jiān)聽器 過濾器 servlet),Spring Cloud GateWay 最主要的功能就是路由轉(zhuǎn)發(fā),而在定義

    2024年02月14日
    瀏覽(29)
  • Spring-Cloud-Gateway如何自定義路由過濾器?

    遇到這么一個面試題:自定義網(wǎng)關(guān)過濾器實(shí)現(xiàn)把url中的請求參數(shù)放到http的header中傳遞給微服務(wù)。 我們知道網(wǎng)關(guān)的一個重要的作用就是路由轉(zhuǎn)發(fā),路由表的配置大概是這個樣子: 其中的filters就是配置的路由過濾器,Spring已經(jīng)內(nèi)置了31個路由的過濾器,這些過濾器都是 org.spring

    2024年02月16日
    瀏覽(24)
  • GateWay網(wǎng)關(guān)自定義過濾器實(shí)現(xiàn)token校驗(yàn)完成統(tǒng)一鑒權(quán)

    GateWay網(wǎng)關(guān)自定義過濾器實(shí)現(xiàn)token校驗(yàn)完成統(tǒng)一鑒權(quán)

    gateWay---API網(wǎng)關(guān),也可以稱為業(yè)務(wù)網(wǎng)關(guān),主要服務(wù)于微服務(wù)的; (1)? 三大組件 路由(Route) ????????構(gòu)建網(wǎng)關(guān)的基本模塊,由id(唯一標(biāo)示)、目標(biāo)URI、一組斷言、一組過濾器組成,如果斷言為true,則匹配該路由 ? 斷言(Predicate) ? ? ? ? ?可以使用它匹配來自HTTP請求的任何

    2024年02月08日
    瀏覽(23)
  • 微服務(wù)Gateway網(wǎng)關(guān)(自動定位/自定義過濾器/解決跨域)+nginx反向代理gateway集群

    微服務(wù)Gateway網(wǎng)關(guān)(自動定位/自定義過濾器/解決跨域)+nginx反向代理gateway集群

    目錄 Gateway網(wǎng)關(guān) 1.0.為什么需要網(wǎng)關(guān)? 1.1.如何使用gateway網(wǎng)關(guān) 1.2.網(wǎng)關(guān)從注冊中心拉取服務(wù) 1.3.gateway自動定位 1.4.gateway常見的斷言 1.5.gateway內(nèi)置的過濾器 1.6.自定義過濾器-全局過濾器 1.7.解決跨域問題 2.nginx反向代理gateway集群 2.1.配置文件 繼? nacos注冊中心+Ribbon負(fù)載均衡+完成

    2024年02月06日
    瀏覽(43)
  • 從Spring Cloud Gateway過濾器中獲取請求體的最優(yōu)方案

    在spring cloud gateway出現(xiàn)這個問題的時候我們第一反應(yīng)應(yīng)該很簡單,但是真正實(shí)現(xiàn)的時候卻有點(diǎn)困難。我看了很多相關(guān)的文檔,感覺太多都不清晰而且解決不了問題。下面我就把我的方便理解的解決方案寫下來。 1. 先重寫請求體(過濾器優(yōu)先級一定要在要獲取body之前執(zhí)行) 這

    2024年02月16日
    瀏覽(22)
  • JAVA開發(fā)(通過網(wǎng)關(guān)gateway過濾器進(jìn)行返回結(jié)果加密)

    JAVA開發(fā)(通過網(wǎng)關(guān)gateway過濾器進(jìn)行返回結(jié)果加密)

    在對C的網(wǎng)站或者APP后端接口中,參數(shù)的傳輸往往需要加密傳輸。這時我們 可以通過springcloud的網(wǎng)關(guān)過濾器進(jìn)行統(tǒng)一的控制。 網(wǎng)關(guān)過濾器的執(zhí)行順序: 請求進(jìn)入網(wǎng)關(guān)會碰到三類過濾器:當(dāng)前路由過濾器、DefaultFilter、GlobalFilter。 請求路由后,會將當(dāng)前路由過濾器和DefaultFilter、

    2023年04月17日
    瀏覽(21)
  • SpringBoot自定義過濾器獲取HttpServletRequest和HttpServletResponse的參數(shù)

    公司的老系統(tǒng)改造:由于接口日志不全,接口太多,也無法每個接口都加上日志,所以要在網(wǎng)關(guān)層統(tǒng)一記錄一下日志,并存到數(shù)據(jù)庫中,(以后計(jì)劃要存儲到ES中) 過濾器是基于Servlet規(guī)范的組件,作用于整個請求和響應(yīng)過程,無法直接訪問Spring MVC的上下文。過濾器先于攔截

    2024年01月25日
    瀏覽(19)
  • Spring MVC獲取參數(shù)和自定義參數(shù)類型轉(zhuǎn)換器及編碼過濾器

    Spring MVC獲取參數(shù)和自定義參數(shù)類型轉(zhuǎn)換器及編碼過濾器

    目錄 ? 一、使用Servlet原生對象獲取參數(shù) 1.1?控制器方法 1.2?測試結(jié)果 二、自定義參數(shù)類型轉(zhuǎn)換器 2.1?編寫類型轉(zhuǎn)換器類 2.2?注冊類型轉(zhuǎn)換器對象? 2.3?測試結(jié)果? 三、編碼過濾器 3.1?JSP表單 3.2?控制器方法 3.3?配置過濾器 3.4 測試結(jié)果? 往期專欄文章相關(guān)導(dǎo)讀? 1. Maven系列專

    2024年02月10日
    瀏覽(32)
  • Gateway網(wǎng)關(guān) 全局過濾器

    Gateway網(wǎng)關(guān) 全局過濾器

    一、全局過濾器 全局過濾器GlobalFilter 全局過濾器的作用也是處理一切進(jìn)入網(wǎng)關(guān)的請求和微服務(wù)響應(yīng),與GatewayFilter的作用一樣。 區(qū)別在于GatewayFilter通過配置定義,處理邏輯是固定的。 需求:定義全局過濾器,攔截請求,判斷請求的參數(shù)是否滿足下面條件: 參數(shù)中是否有au

    2024年02月07日
    瀏覽(23)
  • gateway-過濾器執(zhí)行順序

    請求進(jìn)入網(wǎng)關(guān)會碰到三類過濾器:當(dāng)前路由過濾器、DefaultFilter、GlobalFilter。 請求路由后,會將當(dāng)前路由過濾器和DefaultFilter、GlobalFilter,合并到一個過濾器鏈(集合)中,排序后依次執(zhí)行每個過濾器 過濾器執(zhí)行順序 1.每一個過濾器都必須指定一個int類型的order值,order值越小

    2024年02月13日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包