此ServerHttpResponse指的是org.springframework.http.server.reactive.ServerHttpResponse;
就是gateway当中使用ServerWebExchange得到的一个response。
ServerHttpResponse.writeWith()
某些条件下,我希望在gateway的全局过滤器中直接返回请求,而不进行转发,比如做ip限制这样的功能。
然而GlobalFilter的处理方法中只提供了一个``ServerWebExchange和一个
GatewayFilterChain,然后可以从
ServerWebExchange中调用
getResponse()方法得到一个
ServerHttpResponse`。显然,要想直接返回数据,我们应该在这个response上做工作。刚开始的代码是这样的:
package cn.sticki.gateway.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* ip访问限制过滤器
*
* @author 阿杆
*/
@Slf4j
@Component
public class IpLimitFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 这里可以获取到ServerHttpRequest和ServerHttpResponse
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// do something ...
// 放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -10;
}
}
写入数据到ServerHttpResponse
这东西对我来说并不常用,常用的一般是 HttpResponse
或者 HttpServerResponse
,往 ServerHttpResponse
里面写入数据我压根都不会。这里我卡了好久,各种地方搜,然后还去查了spring gateway的官方文档,都没找到,主要还是自己太菜了,代码不会写,资料还查不到。。。
后来在某个公众号上找到了,有点小复杂,然后根据自己的需求进行了转化,核心代码如下:
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.LOCKED);
DataBufferFactory bufferFactory = response.bufferFactory();
ObjectMapper objectMapper = new ObjectMapper();
DataBuffer wrap = bufferFactory.wrap(objectMapper.writeValueAsBytes(new RestResult<>(408, "访问频繁,请稍后再试")));
return response.writeWith(Mono.fromSupplier(() -> wrap));
完整代码如下(业务逻辑已经被我删掉了):
package cn.sticki.gateway.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
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.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.io.IOException;
import static cn.sticki.gateway.utils.RedisConstants.GATEWAY_IPLIMIT_KEY;
import static cn.sticki.gateway.utils.RedisConstants.GATEWAY_IPLIMIT_TTL;
/**
* @author 阿杆
*/
@Slf4j
@Component
public class IpLimitFilter implements GlobalFilter, Ordered {
@SneakyThrows(IOException.class)
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 打印访问情况
log.info("{} {} {} {}", request.getRemoteAddress(), request.getMethod(), response.getStatusCode(), request.getPath());
// 业务逻辑已经被我删掉了,请根据自己的需求进行修改
if(...){
response.setStatusCode(HttpStatus.LOCKED);
DataBufferFactory bufferFactory = response.bufferFactory();
ObjectMapper objectMapper = new ObjectMapper();
log.info("ip limit : {} {}", ip, exchange.getRequest().getPath());
// 要写入的数据对象,会自动转为json格式
DataBuffer wrap = bufferFactory.wrap(objectMapper.writeValueAsBytes(...);
return response.writeWith(Mono.fromSupplier(() -> wrap));
} else {
// 放行
return chain.filter(exchange);
}
}
@Override
public int getOrder() {
return -10;
}
}