-
-
Save WeirdBob/b25569d461f0f54444d2c0eab51f3c48 to your computer and use it in GitHub Desktop.
spring: | |
cloud: | |
gateway: | |
routes: | |
- id: test | |
uri: https://httpbin.org:443 | |
predicates: | |
- Path=/uuid | |
- Method=GET | |
server: | |
port: 8080 |
package examples; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
@SpringBootApplication | |
@EnableAutoConfiguration | |
public class GatewayApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(GatewayApplication.class, args); | |
} | |
} |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>examples</groupId> | |
<artifactId>gateway</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>2.0.0.M5</version> | |
<relativePath /> <!-- lookup parent from repository --> | |
</parent> | |
<properties> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |
<java.version>1.8</java.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.cloud</groupId> | |
<artifactId>spring-cloud-starter-gateway</artifactId> | |
<version>2.0.0.M3</version> | |
</dependency> | |
</dependencies> | |
<profiles> | |
<profile> | |
<id>spring</id> | |
<activation> | |
<activeByDefault>true</activeByDefault> | |
</activation> | |
<repositories> | |
<repository> | |
<id>spring-milestones</id> | |
<name>Spring Milestones</name> | |
<url>https://repo.spring.io/libs-milestone-local</url> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</repository> | |
</repositories> | |
</profile> | |
</profiles> | |
</project> |
package examples; | |
import java.nio.charset.Charset; | |
import org.reactivestreams.Publisher; | |
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.DataBufferFactory; | |
import org.springframework.http.server.reactive.ServerHttpResponse; | |
import org.springframework.http.server.reactive.ServerHttpResponseDecorator; | |
import org.springframework.stereotype.Component; | |
import org.springframework.web.server.ServerWebExchange; | |
import reactor.core.publisher.Flux; | |
import reactor.core.publisher.Mono; | |
@Component | |
public class ToUppercaseGlobalFilter implements GlobalFilter, Ordered { | |
@Override | |
public int getOrder() { | |
return -2; // -1 is response write filter, must be called before that | |
} | |
@Override | |
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { | |
ServerHttpResponse originalResponse = exchange.getResponse(); | |
DataBufferFactory bufferFactory = originalResponse.bufferFactory(); | |
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { | |
@Override | |
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { | |
if (body instanceof Flux) { | |
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body; | |
return super.writeWith(fluxBody.map(dataBuffer -> { | |
// probably should reuse buffers | |
byte[] content = new byte[dataBuffer.readableByteCount()]; | |
dataBuffer.read(content); | |
byte[] uppedContent = new String(content, Charset.forName("UTF-8")).toUpperCase().getBytes(); | |
return bufferFactory.wrap(uppedContent); | |
})); | |
} | |
return super.writeWith(body); // if body is not a flux. never got there. | |
} | |
}; | |
return chain.filter(exchange.mutate().response(decoratedResponse).build()); // replace response with decorator | |
} | |
} |
@arpitkh12 have you found solution yet?
when i use this to modify a large content,it usually read a part of my json string ,server has no response,do you have meet this question?how can i solve this
you can remove the Content-Length from headers to handle this problem;
thanks for this gist. it steered me towards what i need to modify the response of a body via Spring Cloud Gateway. A lot can be learned from the source code of ModifyResponseBodyGatewayFilterFactory.java
to maybe improve on this but for my purpose the gist works as it is.
edit: oof. that didn't last long 😝. the above approach will work to some degree but it is limited...like, for example, if you intend to modify a JSON response body prior to returning to the client, the above gist will not work (i know because i tried). also note that the gist doesn't take the decoders into account from upstream like here.
I found an article that tackled this and the solution seems to be a modification of ModifyResponseBodyGatewayFilterFactory
.
edit 2: after tinkering around, i was able to write a quick and dirty custom filter that modifies response body based on what ModifyResponseBodyGatewayFilterFactory
does today ...i wrote up a gist here.
https://gist.github.com/MdShohanurRahman/0d27148e7a1c9e05f6542f11c2ad98a0
here is the complete request and response log. You can follow.
@chenkunyun My requirements are to log all incoming request with request body and also make another call to audit service passing the request body and api. The example you have provided is for response body. Can you please tell how would you do that for incoming request ?
I am using DiscoveryClient Route Definition Locator to build routes so cannot add ReadBodyPredicateFactory as it is JAVA DSL based config.