日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gateway请求拦截_spring cloud gateway 拦截request Body

發布時間:2025/3/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gateway请求拦截_spring cloud gateway 拦截request Body 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在接入Spring-Cloud-Gateway時,可能有需求進行緩存Json-Body數據或者Form-Urlencoded數據的情況。

由于Spring-Cloud-Gateway是以WebFlux為基礎的響應式架構設計,所以在原有Zuul基礎上遷移過來的過程中,傳統的編程思路,并不適合于Reactor Stream的開發。

網絡上有許多緩存案例,但是在測試過程中出現各種Bug問題,在緩存Body時,需要考慮整體的響應式操作,才能更合理的緩存數據

下面提供緩存Json-Body數據或者Form-Urlencoded數據的具體實現方案,該方案經測試,滿足各方面需求,以及避免了網絡上其他緩存方案所出現的問題

定義一個GatewayContext類,用于存儲請求中的數據

import org.springframework.util.MultiValueMap;

public class GatewayContext {

public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";

/**

* cache json body

*/

private String cacheBody;

/**

* cache formdata

*/

private MultiValueMap formData;

/**

* cache reqeust path

*/

private String path;

public String getCacheBody() {

return cacheBody;

}

public void setCacheBody(String cacheBody) {

this.cacheBody = cacheBody;

}

public MultiValueMap getFormData() {

return formData;

}

public void setFormData(MultiValueMap formData) {

this.formData = formData;

}

public String getPath() {

return path;

}

public void setPath(String path) {

this.path = path;

}

}

1 . 該示例只支持緩存下面3種MediaType

APPLICATION_JSON--Json數據

APPLICATION_JSON_UTF8--Json數據

APPLICATION_FORM_URLENCODED--FormData表單數據

2 . 經驗總結:

在緩存Body時,不能夠在Filter內部直接進行緩存,需要按照響應式的處理方式,在異步操作路途上進行緩存Body,由于Body只能讀取一次,所以要讀取完成后要重新封裝新的request和exchange才能保證請求正常傳遞到下游

在緩存FormData時,FormData也只能讀取一次,所以在讀取完畢后,需要重新封裝request和exchange,這里要注意,如果對FormData內容進行了修改,則必須重新定義Header中的content-length已保證傳輸數據的大小一致

package com.weiresearch.idss.weiark.gateway.LogReader;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

import java.nio.charset.Charset;

import java.nio.charset.StandardCharsets;

import java.util.List;

import java.util.Map;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.core.io.ByteArrayResource;

import org.springframework.core.io.buffer.DataBuffer;

import org.springframework.core.io.buffer.DataBufferUtils;

import org.springframework.core.io.buffer.NettyDataBufferFactory;

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpMethod;

import org.springframework.http.MediaType;

import org.springframework.http.codec.HttpMessageReader;

import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.http.server.reactive.ServerHttpRequestDecorator;

import org.springframework.stereotype.Component;

import org.springframework.util.MultiValueMap;

import org.springframework.web.reactive.function.server.HandlerStrategies;

import org.springframework.web.reactive.function.server.ServerRequest;

import org.springframework.web.server.ServerWebExchange;

import io.netty.buffer.ByteBufAllocator;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

// https://segmentfault.com/a/1190000017898354

@Component

public class GatewayContextFilter

implements GlobalFilter {

/**

* default HttpMessageReader

*/

private static final List> messageReaders =

HandlerStrategies.withDefaults().messageReaders();

private Logger log = LoggerFactory.getLogger(GatewayContextFilter.class);

@Override

public Mono filter(

ServerWebExchange exchange,

GatewayFilterChain chain) {

/**

* save request path and serviceId into gateway context

*/

ServerHttpRequest request = exchange.getRequest();

String path = request.getPath().pathWithinApplication().value();

GatewayContext gatewayContext = new GatewayContext();

gatewayContext.setPath(path);

/**

* save gateway context into exchange

*/

exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT,

gatewayContext);

HttpHeaders headers = request.getHeaders();

MediaType contentType = headers.getContentType();

log.info("start-------------------------------------------------");

log.info("HttpMethod:{},Url:{}", request.getMethod(),

request.getURI().getRawPath());

if (request.getMethod() == HttpMethod.GET) {

log.info("end-------------------------------------------------");

}

if (request.getMethod() == HttpMethod.POST) {

Mono voidMono = null;

if (MediaType.APPLICATION_JSON.equals(contentType)

|| MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {

voidMono =

readBody(exchange, chain, gatewayContext);

}

if (MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) {

voidMono =

readFormData(exchange, chain, gatewayContext);

}

return voidMono;

}

/* log.debug(

"[GatewayContext]ContentType:{},Gateway context is set with {}",

contentType, gatewayContext);*/

return chain.filter(exchange);

}

/**

* ReadFormData

*

* @param exchange

* @param chain

* @return

*/

private Mono readFormData(

ServerWebExchange exchange,

GatewayFilterChain chain,

GatewayContext gatewayContext) {

final ServerHttpRequest request = exchange.getRequest();

HttpHeaders headers = request.getHeaders();

return exchange.getFormData()

.doOnNext(multiValueMap -> {

gatewayContext.setFormData(multiValueMap);

log.info("Post x-www-form-urlencoded:{}",

multiValueMap);

log.info(

"end-------------------------------------------------");

})

.then(Mono.defer(() -> {

Charset charset = headers.getContentType().getCharset();

charset = charset == null ? StandardCharsets.UTF_8 : charset;

String charsetName = charset.name();

MultiValueMap formData =

gatewayContext.getFormData();

/**

* formData is empty just return

*/

if (null == formData || formData.isEmpty()) {

return chain.filter(exchange);

}

StringBuilder formDataBodyBuilder = new StringBuilder();

String entryKey;

List entryValue;

try {

/**

* repackage form data

*/

for (Map.Entry> entry : formData

.entrySet()) {

entryKey = entry.getKey();

entryValue = entry.getValue();

if (entryValue.size() > 1) {

for (String value : entryValue) {

formDataBodyBuilder.append(entryKey).append("=")

.append(

URLEncoder.encode(value, charsetName))

.append("&");

}

} else {

formDataBodyBuilder

.append(entryKey).append("=").append(URLEncoder

.encode(entryValue.get(0), charsetName))

.append("&");

}

}

} catch (UnsupportedEncodingException e) {

// ignore URLEncode Exception

}

/**

* substring with the last char '&'

*/

String formDataBodyString = "";

if (formDataBodyBuilder.length() > 0) {

formDataBodyString = formDataBodyBuilder.substring(0,

formDataBodyBuilder.length() - 1);

}

/**

* get data bytes

*/

byte[] bodyBytes = formDataBodyString.getBytes(charset);

int contentLength = bodyBytes.length;

ServerHttpRequestDecorator decorator =

new ServerHttpRequestDecorator(

request) {

/**

* change content-length

*

* @return

*/

@Override

public HttpHeaders getHeaders() {

HttpHeaders httpHeaders = new HttpHeaders();

httpHeaders.putAll(super.getHeaders());

if (contentLength > 0) {

httpHeaders.setContentLength(contentLength);

} else {

httpHeaders.set(HttpHeaders.TRANSFER_ENCODING,

"chunked");

}

return httpHeaders;

}

/**

* read bytes to Flux

*

* @return

*/

@Override

public Flux getBody() {

return DataBufferUtils

.read(new ByteArrayResource(bodyBytes),

new NettyDataBufferFactory(

ByteBufAllocator.DEFAULT),

contentLength);

}

};

ServerWebExchange mutateExchange =

exchange.mutate().request(decorator).build();

/* log.info("[GatewayContext]Rewrite Form Data :{}",

formDataBodyString);*/

return chain.filter(mutateExchange);

}));

}

/**

* ReadJsonBody

*

* @param exchange

* @param chain

* @return

*/

private Mono readBody(

ServerWebExchange exchange,

GatewayFilterChain chain,

GatewayContext gatewayContext) {

/**

* join the body

*/

return DataBufferUtils.join(exchange.getRequest().getBody())

.flatMap(dataBuffer -> {

/*

* read the body Flux, and release the buffer

* //TODO when SpringCloudGateway Version Release To G.SR2,this can be update with the new version's feature

* see PR https://github.com/spring-cloud/spring-cloud-gateway/pull/1095

*/

byte[] bytes = new byte[dataBuffer.readableByteCount()];

dataBuffer.read(bytes);

DataBufferUtils.release(dataBuffer);

Flux cachedFlux = Flux.defer(() -> {

DataBuffer buffer =

exchange.getResponse().bufferFactory().wrap(bytes);

DataBufferUtils.retain(buffer);

return Mono.just(buffer);

});

/**

* repackage ServerHttpRequest

*/

ServerHttpRequest mutatedRequest =

new ServerHttpRequestDecorator(exchange.getRequest()) {

@Override

public Flux getBody() {

return cachedFlux;

}

};

/**

* mutate exchage with new ServerHttpRequest

*/

ServerWebExchange mutatedExchange =

exchange.mutate().request(mutatedRequest).build();

/**

* read body string with default messageReaders

*/

return ServerRequest.create(mutatedExchange, messageReaders)

.bodyToMono(String.class)

.doOnNext(objectValue -> {

log.info("PostBody:{}", objectValue);

log.info(

"end-------------------------------------------------");

gatewayContext.setCacheBody(objectValue);

/* log.debug("[GatewayContext]Read JsonBody:{}",

objectValue);*/

}).then(chain.filter(mutatedExchange));

});

}

}

在后續Filter中,可以直接從ServerExchange中獲取GatewayContext,就可以獲取到緩存的數據,如果需要緩存其他數據,則可以根據自己的需求,添加到GatewayContext中即可

GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);

總結

以上是生活随笔為你收集整理的gateway请求拦截_spring cloud gateway 拦截request Body的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美日韩综合一区二区 | 阿v视频在线免费观看 | 国产成人自拍网 | 日本真人做爰免费视频120秒 | 自拍视频在线播放 | 色狠狠综合网 | 亚洲国产精品网站 | 激烈娇喘叫1v1高h糙汉 | 毛片无码免费无码播放 | 老司机深夜网站 | 亚洲一区二区国产精品 | 亚洲成人aa | 男人晚上看的视频 | 欧美三级精品 | 成人在线视频一区 | 伊人久久艹 | 亚洲人成网址 | 综合久| 亚洲 欧美 变态 另类 综合 | 播放美国生活大片 | 日本天堂在线观看 | 误杀1电影免费观看高清完整版 | 国产经典三级在线 | 久久久久麻豆 | 女的高潮流时喷水图片大全 | 国产情侣自拍小视频 | 中文无码熟妇人妻av在线 | 我和公激情中文字幕 | 亚洲黄色av网站 | 白浆一区| 亚洲自拍av在线 | 欧美日韩在线播放 | 国产夫妻av| 青青操网| 中文字幕在线视频观看 | 强侵犯の奶水授乳羞羞漫虐 | 国产视频久久久久久 | 欧美少妇激情 | 香蕉av在线播放 | 久久中文字幕高清 | 二级毛片视频 | 狠狠干成人 | 狠狠干一区| 日本中文字幕免费观看 | 岛国在线视频 | 亚洲精品大全 | 亚洲精品白浆高清久久久久久 | 国产黄色片子 | 欧美色老头old∨ideo | 亚洲午夜18毛片在线看 | 精品国产av无码一区二区三区 | 真实乱视频国产免费观看 | 久久超碰在线 | 精品福利一区 | 四季av一区二区凹凸精品 | 熊出没之冬日乐翻天免费高清观看 | 精品国产乱码久久久久久久 | 免费av影视 | 日本高清在线播放 | 国产精品剧情一区 | 永久免费未满 | 永久免费不卡在线观看黄网站 | a级片在线观看视频 | 蜜桃91丨九色丨蝌蚪91桃色 | 精品一区二区三区三区 | 黄色av高清 | 极品福利视频 | 亚洲精品久久久久久久蜜桃 | 经典三级视频 | av天天草| 不卡视频一区二区 | 亚洲欧美日韩一区二区三区四区 | 91成人精品国产刺激国语对白 | 精品无码一区二区三区电影桃花 | 少妇高潮惨叫久久久久 | 放几个免费的毛片出来看 | 精品国产鲁一鲁一区二区张丽 | 久草中文在线观看 | 日韩有码在线观看 | 91亚洲天堂 | 成人在线日韩 | 久操热线 | 91久久精品国产91性色tv | 性xxxxbbbb | 亚日韩av| 亚州国产精品 | 九九这里只有精品视频 | 丰满少妇一区二区 | 日本一级理论片在线大全 | 活大器粗np高h一女多夫 | 国产精品主播 | 亚洲成人一二三区 | 波多野结衣1区 | 成人免费久久 | 男女黄色片 | 免费久久av| 欧美日韩黄色一区二区 | 一级毛片黄片 | 在线看国产视频 |