-
-
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 | |
} | |
} |
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.
you can remove the Content-Length from headers to handle this problem;