背景介绍
有个业务需求,要提供一套API接口给第三方调用。
在处理具体业务接口之前,设计上要先做个简单的鉴权,协商拟定了身份传参后,考虑到项目上已经用到了Spring Cloud Gateway ,就统一在网关模块做身份校验。
所以在服务端获取到请求的时候,要先拦截获取到请求传参,才能做后续的鉴权逻辑。
这里就需要解决一个问题:Spring Cloud Gateway 怎么读取请求传参?
搜索关键词:spring cloud gateway get request body
问题描述
问题:Spring Cloud Gateway 读取请求传参
这里只简单处理两种情况,get请求和post请求。
如果发现是get请求,就取url上的参数;
如果发现是post请求,就读取body的内容。
解决方案
参考 https://github.com/spring-cloud/spring-cloud-gateway/issues/747
定义了两个过滤器 filter,第一个过滤器ApiRequestFilter
获取参数,放到上下文 GatewayContext
。
注意如果是POST请求,请求体读取完后,要重新构造,填回请求体中。
第二个过滤器ApiVerifyFilter
, 从上下文可以直接获取到参数。
后面如果其他业务也有读取参数的需求,就直接从上下文获取,不用再重复写获取参数的逻辑。
实现代码
GatewayContext
@Data
public class GatewayContext {
public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";
/**
* cache json body
*/
private String cacheBody;
/**
* cache form data
*/
private MultiValueMap<String, Part> formData;
/**
* cache request path
*/
private String path;
}
ApiRequestFilter
@Component
@Slf4j
public class ApiRequestFilter implements GlobalFilter, Ordered {
private static AntPathMatcher antPathMatcher;
static {
antPathMatcher = new AntPathMatcher();
}
/**
* default HttpMessageReader
*/
private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
private static final ResolvableType MULTIPART_DATA_TYPE = ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
private static final Mono<MultiValueMap<String, Part>> EMPTY_MULTIPART_DATA = Mono.just(CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<String, Part>(0))).cache();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String url = request.getURI().getPath();
if(request.getMethod() == HttpMethod.GET){
// get请求 处理参数
return handleGetMethod(exchange, chain, request);
}
if(request.getMethod() == HttpMethod.POST){
// post请求 处理参数
return handlePostMethod(exchange, chain, request);
}
return chain.filter(exchange);
}
/**
* get请求 处理参数
* @param exchange
* @param chain
* @param request
* @return
*/
private Mono<Void> handleGetMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request) {
// TODO 暂时不做处理
return chain.filter(exchange);
}
/**
* post请求 校验参数
* @param exchange
* @param chain
* @param request
* @return
*/
private Mono<Void> handlePostMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request){
GatewayContext gatewayContext = new GatewayContext();
gatewayContext.setPath(request.getPath().pathWithinApplication().value())