Spring Cloud Gateway 修改响应数据

import org.springframework.web.reactive.function.BodyInserter;

import org.springframework.web.reactive.function.BodyInserters;

import org.springframework.web.reactive.function.client.ExchangeStrategies;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

public class ModifyResponseBodyGatewayFilterFactory extends AbstractGatewayFilterFactory<ModifyResponseBodyGatewayFilterFactory.Config> {

private final ServerCodecConfigurer codecConfigurer;

public ModifyResponseBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {

super(ModifyResponseBodyGatewayFilterFactory.Config.class);

this.codecConfigurer = codecConfigurer;

}

public GatewayFilter apply(ModifyResponseBodyGatewayFilterFactory.Config config) {

return new ModifyResponseBodyGatewayFilterFactory.ModifyResponseGatewayFilter(config);

}

public static class Config {

private Class inClass;

private Class outClass;

private Map<String, Object> inHints;

private Map<String, Object> outHints;

private String newContentType;

private RewriteFunction rewriteFunction;

public Config() {

}

public Class getInClass() {

return this.inClass;

}

public ModifyResponseBodyGatewayFilterFactory.Config setInClass(Class inClass) {

this.inClass = inClass;

return this;

}

public Class getOutClass() {

return this.outClass;

}

public ModifyResponseBodyGatewayFilterFactory.Config setOutClass(Class outClass) {

this.outClass = outClass;

return this;

}

public Map<String, Object> getInHints() {

return this.inHints;

}

public ModifyResponseBodyGatewayFilterFactory.Config setInHints(Map<String, Object> inHints) {

this.inHints = inHints;

return this;

}

public Map<String, Object> getOutHints() {

return this.outHints;

}

public ModifyResponseBodyGatewayFilterFactory.Config setOutHints(Map<String, Object> outHints) {

this.outHints = outHints;

return this;

}

public String getNewContentType() {

return this.newContentType;

}

public ModifyResponseBodyGatewayFilterFactory.Config setNewContentType(String newContentType) {

this.newContentType = newContentType;

return this;

}

public RewriteFunction getRewriteFunction() {

return this.rewriteFunction;

}

public <T, R> ModifyResponseBodyGatewayFilterFactory.Config setRewriteFunction(Class inClass, Class outClass, RewriteFunction<T, R> rewriteFunction) {

this.setInClass(inClass);

this.setOutClass(outClass);

this.setRewriteFunction(rewriteFunction);

return this;

}

public ModifyResponseBodyGatewayFilterFactory.Config setRewriteFunction(RewriteFunction rewriteFunction) {

this.rewriteFunction = rewriteFunction;

return this;

}

}

public class ResponseAdapter implements ClientHttpResponse {

private final Flux flux;

private final HttpHeaders headers;

public ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {

this.headers = headers;

if (body instanceof Flux) {

this.flux = (Flux)body;

} else {

this.flux = ((Mono)body).flux();

}

}

public Flux getBody() {

return this.flux;

}

public HttpHeaders getHeaders() {

return this.headers;

}

public HttpStatus getStatusCode() {

return null;

}

public int getRawStatusCode() {

return 0;

}

public MultiValueMap<String, ResponseCookie> getCookies() {

return null;

}

}

public class ModifyResponseGatewayFilter implements GatewayFilter, Ordered {

private final ModifyResponseBodyGatewayFilterFactory.Config config;

public ModifyResponseGatewayFilter(ModifyResponseBodyGatewayFilterFactory.Config config) {

this.config = config;

}

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {

public Mono writeWith(Publisher<? extends DataBuffer> body) {

Class inClass = ModifyResponseGatewayFilter.this.config.getInClass();

Class outClass = ModifyResponseGatewayFilter.this.config.getOutClass();

MediaType originalResponseContentType = (MediaType)exchange.getAttribute(“original_response_content_type”);

HttpHeaders httpHeaders = new HttpHeaders();

httpHeaders.setContentType(originalResponseContentType);

ModifyResponseBodyGatewayFilterFactory.ResponseAdapter responseAdapter = ModifyResponseBodyGatewayFilterFactory.this.new ResponseAdapter(body, httpHeaders);

DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());

Mono modifiedBody = clientResponse.bodyToMono(inClass).flatMap((originalBody) -> {

return ModifyResponseGatewayFilter.this.config.rewriteFunction.apply(exchange, originalBody);

});

BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);

CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());

return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {

long contentLength1 = this.getDelegate().getHeaders().getContentLength();

Flux messageBody = outputMessage.getBody();

HttpHeaders headers = this.getDelegate().getHeaders();

if (!headers.containsKey(“Transfer-Encoding”)) {

messageBody = messageBody.doOnNext((data) -> {

headers.setContentLength((long)data.readableByteCount());

});

}

return this.getDelegate().writeWith(messageBody);

}));

}

public Mono writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {

return this.writeWith(Flux.from(body).flatMapSequential(§ -> {

return p;

}));

}

};

return chain.filter(exchange.mutate().response(responseDecorator).build());

}

public int getOrder() {

return -2;

}

}

}

复制代码

实现代码

====

根据源码示例,可以在网关过滤器添加类似逻辑,实现修改响应数据。

ResponseFilter


@Component

@Slf4j

public class ResponseFilter implements GlobalFilter, Ordered {

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpRequest request = exchange.getRequest();

URI uri = request.getURI();

String url = uri.getPath();

HttpStatus statusCode = exchange.getResponse().getStatusCode();

if(Objects.equals(statusCode, HttpStatus.BAD_REQUEST) || Objects.equals(statusCode, HttpStatus.TOO_MANY_REQUESTS)){

// 如果是特殊的请求,已处理响应内容,这里不再处理

return chain.filter(exchange);

}

// 根据具体业务内容,修改响应体

return modifyResponseBody(exchange, chain);

}

/**

  • 修改响应体

  • @param exchange

  • @param chain

  • @return

*/

private Mono modifyResponseBody(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {

public Mono writeWith(Publisher<? extends DataBuffer> body) {

MediaType originalResponseContentType = (MediaType)exchange.getAttribute(“original_response_content_type”);

HttpHeaders httpHeaders = new HttpHeaders();

AtomicBoolean isHttpCodeOK = new AtomicBoolean(true);

httpHeaders.setContentType(originalResponseContentType);

ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders);

HttpStatus statusCode = this.getStatusCode();

// 修改后的响应体

Mono modifiedBody = getModifiedBody(statusCode, isHttpCodeOK, responseAdapter, exchange);

// 业务上的开关,表示是否开启加密,如果开启,就需要修改响应体,将响应体数据加密。开关从上下文获取。这里只关心是一个boolean值即可。

Boolean flag;

BodyInserter bodyInserter;

if(!flag) {

// 不需要修改响应数据

bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);

}else {

// 需要修改响应数据

// 这里最后采用了 ByteArrayResource 类去处理

bodyInserter = BodyInserters.fromPublisher(modifiedBody, ByteArrayResource.class);

}

CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, httpHeaders);

return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {

Flux messageBody = outputMessage.getBody();

ServerHttpResponse httpResponse = this.getDelegate();

HttpHeaders headers = httpResponse.getHeaders();

if (!headers.containsKey(“Transfer-Encoding”)) {

messageBody = messageBody.doOnNext((data) -> {

headers.setContentLength((long)data.readableByteCount());

});

}

if(!isHttpCodeOK.get()){

// 业务处理不是200,说明有异常,设置httpCode状态码是500

httpResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);

}

return httpResponse.writeWith(messageBody);

}));

}

public Mono writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {

return this.writeWith(Flux.from(body).flatMapSequential(§ -> {

return p;

}));

}

};

return chain.filter(exchange.mutate().response(responseDecorator).build());

}

public class ResponseAdapter implements ClientHttpResponse {

private final Flux flux;

private final HttpHeaders headers;

public ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {

this.headers = headers;

if (body instanceof Flux) {

this.flux = (Flux)body;

} else {

this.flux = ((Mono)body).flux();

}

}

public Flux getBody() {

return this.flux;

}

public HttpHeaders getHeaders() {

return this.headers;

}

public HttpStatus getStatusCode() {

return null;

}

public int getRawStatusCode() {

return 0;

}

public MultiValueMap<String, ResponseCookie> getCookies() {

return null;

}

}

@Override

public int getOrder() {

return FilterOrderConstant.getOrder(this.getClass().getName());

}

private Mono getModifiedBody(HttpStatus httpStatus, AtomicBoolean isHttpCodeOK, ResponseAdapter responseAdapter, ServerWebExchange exchange){

switch (httpStatus){

// 业务上需要特殊处理的状态码

case BAD_REQUEST:

case METHOD_NOT_ALLOWED:

isHttpCodeOK.set(false);

return getMono(HttpCode.BAD_REQUEST, exchange);

case INTERNAL_SERVER_ERROR:

isHttpCodeOK.set(false);

return getMono(HttpCode.SERVER_ERROR, exchange);

default:

// 主要处理流程

return getNormalBody(isHttpCodeOK, responseAdapter, exchange);

}

}

private Mono getNormalBody(AtomicBoolean isHttpCodeOK, ResponseAdapter responseAdapter, ServerWebExchange exchange){

DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());

return clientResponse.bodyToMono(String.class).flatMap((originalBody) -> {

// 业务上的开关,表示是否开启加密,如果开启,就需要修改响应体,将响应体数据加密。开关从上下文获取。这里只关心是一个boolean值即可。

Boolean flag;

ObjectMapper objectMapper = new ObjectMapper();

try {

R r = objectMapper.readValue(originalBody, R.class);

/**

  • 异常处理流程

*/

if(!r.getCode().equals(HttpCode.SUCCESS.getCode())){

// 业务处理不是200,说明有异常,直接返回对应错误

isHttpCodeOK.set(false);

ErrorR errorR = new ErrorR()

.setCode(r.getCode())

.setMsg(r.getMsg());

String json = objectMapper.writeValueAsString(errorR);

log.info(“json = {}”, json);

if(!flag) {

// 不需要加密,则不修改响应体

return Mono.just(json);

}else {

// 对返回数据进行加密 EncryptionUtil.encrypt(json, key)

// 具体加密逻辑不再阐述,这里可以理解成string 转成 byte[] 处理

byte[] encrypt = EncryptionUtil.encrypt(“{}”, key);

ByteArrayResource byteArrayResource = new ByteArrayResource(encrypt);

// 修改响应体,使用 byteArrayResource 封装

return Mono.just(byteArrayResource);

}

}

// 业务处理是200,截取data内容

Object data = r.getData();

if(null == data){

// 返回数据如果为空,则返回空对象

if(!flag) {

// 不需要加密,则不修改响应体

return Mono.just(“{}”);

}else {

// 对返回数据进行加密 EncryptionUtil.encrypt(json, key)

// 具体加密逻辑不再阐述,这里可以理解成string 转成 byte[] 处理

byte[] encrypt = EncryptionUtil.encrypt(“{}”, key);

ByteArrayResource byteArrayResource = new ByteArrayResource(encrypt);

return Mono.just(byteArrayResource);

}

}

/**

  • 主要处理流程

*/

String json = objectMapper.writeValueAsString(data);

if(!flag) {

// 不需要加密,则不修改响应体

return Mono.just(json);

}else {

// 对返回数据进行加密 EncryptionUtil.encrypt(json, key)

// 具体加密逻辑不再阐述,这里可以理解成string 转成 byte[] 处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值