过滤器工厂(修改请求)
AddRequestHeader过滤器工厂
代码语言:txt复制- AddRequestHeader=from,abc
RemoveRequestHeader过滤器工厂
代码语言:txt复制- RemoveRequestHeader=from2
SetStatus过滤器工厂
代码语言:txt复制- id: statusFilter
uri: http://www.example.com/
predicates:
- Query=foo,b1
filters:
- SetStatus=401
RedirectTo过滤器工厂
代码语言:txt复制- id: redictFilter
uri: http://www.example.com/
predicates:
- Query=foo,b2
filters:
- RedirectTo=302,http://weibo.com
自定义过滤器工厂
- 自定义过滤器配置
- id: lb-info
uri: lb://consul-server-producer
predicates:
- Path=/info/**
filters:
- RemoveRequestHeader=from2
- AddRequestHeader=from,abc
- name: Login
args:
checkLogin: true
- 自定义过滤器代码@Slf4j
@Component
public class LoginGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginCfg> {
public LoginGatewayFilterFactory() {
super(LoginCfg.class);
}
@Override
public GatewayFilter apply(LoginCfg loginCfg) {
return (exchange, chain) -> {
log.info("if us check login:" loginCfg.isCheckLogin());
ServerHttpRequest request = exchange.getRequest().mutate()
.build();
if (loginCfg.isCheckLogin()) {
log.info("do login checking.......");
}
return chain.filter(exchange.mutate().request(request).build());
};
}
}
全局过滤器
自定义全局过滤器
代码语言:txt复制package cn.beckbi.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;
/**
* @program: spring-cloud
* @description:
* @author: bikang
* @create: 2022-08-21 20:21
*/
@Slf4j
@Configuration
public class GlobalFilterConfig {
@Bean
@Order(-2)
public GlobalFilter filter1() {
return (exchange, chain) -> {
log.info("filter1 pre");
return chain.filter(
exchange
).then(
Mono.fromRunnable(()->{
log.info("filter1 post");
})
);
};
}
@Bean
@Order(0)
public GlobalFilter filter2() {
return (exchange, chain) -> {
log.info("filter2 pre");
return chain.filter(
exchange
).then(
Mono.fromRunnable(()->{
log.info("filter2 post");
})
);
};
}
@Bean
@Order(2)
public GlobalFilter filter3() {
return (exchange, chain) -> {
log.info("filter3 pre");
return chain.filter(
exchange
).then(
Mono.fromRunnable(()->{
log.info("filter3 post");
})
);
};
}
}
自定义拦截器
代码语言:txt复制package cn.beckbi.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.loadbalancer.ResponseData;
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.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Map;
import java.util.Objects;
/**
* @program: spring-cloud
* @description:
* @author: bikang
* @create: 2022-08-21 20:29
*/
@Slf4j
@Component
public class UserFilter implements GlobalFilter, Ordered {
@Builder
@Data
static class Resp {
private int code;
private String msg;
}
private static final String BAD_CID = "123";
private ObjectMapper mapper = new ObjectMapper();
@Override
public int getOrder(){
return 0;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
boolean matchFilter = false;
if (Objects.nonNull(queryParams) && Objects.nonNull(queryParams.get("cid"))) {
String cid = queryParams.get("cid").get(0);
if (Objects.nonNull(cid) && BAD_CID.equals(cid)) {
matchFilter = true;
}
}
if (matchFilter) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
Resp resp = Resp.builder()
.code(401)
.msg("非法请求")
.build();
DataBuffer dataBuffer = serverHttpResponse.bufferFactory().wrap(
this.getJsonBytes(resp)
);
serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
serverHttpResponse.getHeaders().add("Content-Type", "application/json; charset=utf-8");
return serverHttpResponse.writeWith(Mono.just(dataBuffer));
}
return chain.filter(exchange);
}
private byte[] getJsonBytes(Object o) {
try {
return mapper.writeValueAsBytes(o);
}catch (JsonProcessingException e) {
log.error("json error", e);
}
return "".getBytes();
}
}
http://127.0.0.1:10011/info/1231212312?cid=123
限流器代码:基于redis做限流
代码语言:txt复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
代码语言:txt复制package cn.beckbi.limiter;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;
import java.util.Objects;
/**
* @program: spring-cloud
* @description:
* @author: bikang
* @create: 2022-08-21 21:02
*/
@Configuration
public class LimiterConfig {
@Bean("ipKeyResolver")
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName()
);
}
@Bean("cidKeyResolver")
public KeyResolver cidKeyResolver() {
return exchange -> Mono.just(
Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("cid"))
);
}
@Primary
@Bean("apiKeyResolver")
public KeyResolver apiKeyResolver() {
return exchange -> {
Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
return Mono.just(
route.getId() "#" exchange.getRequest().getPath().value()
);
};
}
}
限流器配置
代码语言:txt复制- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
key-resolver: "#{@apiKeyResolver}"
全局路由处理器
代码语言:txt复制package cn.beckbi.errorhandler;
import cn.beckbi.util.JsonUtil;
import lombok.Builder;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;
/**
* @program: spring-cloud
* @description:
* @author: bikang
* @create: 2022-08-21 21:36
*/
@Component
@Slf4j
@Order(-1)
public class JsonHandler implements ErrorWebExceptionHandler {
@Builder
@Data
static class Msg {
int code;
String msg;
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
ServerHttpRequest request = exchange.getRequest();
String rawQuery = request.getURI().getRawQuery();
String query = StringUtils.hasText(rawQuery) ? "?" rawQuery : "";
String path = request.getPath() query ;
String message ;
HttpStatus status = null;
if (ex instanceof ResponseStatusException) {
status = ((ResponseStatusException) ex).getStatus();
}
if (status == null){
status = HttpStatus.INTERNAL_SERVER_ERROR;
}
// 通过状态码自定义异常信息
if (status.value() >= 400 && status.value() < 500){
message = "路由服务不可达或禁止访问!";
}else {
message = "路由服务异常!";
}
message = " path:" path;
Msg msg = Msg.builder().code(status.value())
.msg(message)
.build();
return response
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
return bufferFactory.wrap(JsonUtil.getJsonBytes(msg));
}));
}
}
代码路径: https://github.com/beckbikang/spring-cloud/tree/main/kgateway