我有一个Spring Cloud Gateway应用程序,我想实现一个过滤器,它在将响应传递给客户端之前读取响应体。下面是自定义过滤器的代码:
@Component
public class CreateResourceGatewayFilterFactory extends AbstractGatewayFilterFactory<CreateResourceGatewayFilterFactory.Config> implements Ordered {
private static final Logger log = LoggerFactory.getLogger(CreateResourceGatewayFilterFactory.class);
public static class Config {
private ResourceType resourceType;
private String requiredRoles;
public ResourceType getResourceType() {
return resourceType;
}
public void setResourceType(ResourceType resourceType) {
this.resourceType = resourceType;
}
public String getRequiredRoles() {
return requiredRoles;
}
public void setRequiredRoles(String requiredRoles) {
this.requiredRoles = requiredRoles;
}
}
public CreateResourceGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
List<String> order = new ArrayList<>(2);
order.add("resourceType");
order.add("requiredRoles");
return order;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
log.debug("Received request at CreateResource filter.");
return chain.filter(exchange.mutate().request(getDecoratedRequest(exchange.getRequest())).response(getDecoratedResponse(exchange.getResponse(), config.getResourceType())).build());
};
}
private ServerHttpResponseDecorator getDecoratedResponse(ServerHttpResponse response, ResourceType resourceType) {
return new ServerHttpResponseDecorator(response) {
@Override
public Mono<Void> writeWith(final Publisher<? extends DataBuffer> body) {
log.debug("Inside response decorator");
if (body instanceof Flux) {
log.debug("Received response from microservice.");
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxBody.buffer()
.map(dataBuffers -> {
DefaultDataBuffer joinedBuffers = new DefaultDataBufferFactory().join(dataBuffers);
byte[] content = new byte[joinedBuffers.readableByteCount()];
joinedBuffers.read(content);
String responseBody = new String(content, StandardCharsets.UTF_8);
log.debug("Buffered response parsed to String {}", responseBody);
return responseBody;
})
.flatMap(responseBody -> doSomething(resourceType, responseBody))
.map(responseBody -> response.bufferFactory().wrap(responseBody.getBytes())))
.onErrorResume(err -> {
log.error("Error extracting resoruce from message {}",err.getMessage());
return Mono.empty();
});
}
return super.writeWith(body);
}
};
}
private Flux<String> doSomething(ResourceType resourceType, String payload) {
// DO SOMETHING WITH PAYLOAD
return Flux.just(payload);
}
private ServerHttpRequest getDecoratedRequest(ServerHttpRequest request) {
return new ServerHttpRequestDecorator(request) {
@Override
public Flux<DataBuffer> getBody() {
log.debug("requestId: {}, method: {} , url: {}", request.getId(), request.getMethodValue(), request.getURI());
return request.getBody();
}
};
}
@Override
public int getOrder() {
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
}
我用的是post as reference。getDecoratedResponse
是创建ServerHttpResponseDecorator
对象的方法。CreateResourceGatewayFilterFactory
是过滤器类,Config
是配置类,它指定将传递给过滤器的参数。application.yml
中的DSL是:
spring:
cloud:
gateway:
default-filters:
- TokenRelay
discovery:
locator:
enabled: true
lower-case-service-id: true
predicates:
- name: Path
args:
pattern: "'/services/'+serviceId.toLowerCase()+'/**'"
filters:
- name: RewritePath
args:
regexp: "'/services/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
routes:
- id: sample_route
uri: http://localhost:8097
predicates:
- Method=POST
- Path=/api/resources/**
filters:
- CreateResource=DEVICE,SUPER_ADMIN
请求在过滤器和请求装饰器中被捕获,因为我可以看到日志,但是没有来自响应装饰器的日志。
响应的HTTP状态代码为201
。
我需要帮助来理解为什么响应装饰器没有被触发。
注意:这个过滤器的目的是读取响应正文。此进程可以在differnet线程中运行,因为它在将响应体发送回客户端之前不会修改响应体。如果有比ServerHttpResponseDecorator
更好的方法,请给我建议。可能是后过滤器逻辑。
1条答案
按热度按时间g6ll5ycj1#
***我已经解决了这个问题。修饰后的响应是通过Webfilter调用的,而不是通过Gateway filter调用的。
你可以在API gateway中引用这段代码