spring-cloud-gateway 功能-解析请求的中的请求参数
基于webflux
场景
当我们要进行接口签名验证的时候,就会获取request中的请求参数,特别是 获取完body数据的时候,转发给业务系统时,发现这个请求中的body不能再用了,所以需要利用request, 即将原始的request进行缓存
RequestParamExtractFilter
缓存 request, 顺序要排在过滤器比较前面!!
public class RequestParamExtractFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
MediaType contentType = headers.getContentType();
//如果是上传请求
if (contentType != null && contentType == MediaType.MULTIPART_FORM_DATA) {
//如果是上传接口则不校验
return chain.filter(exchange);
}
RequestParamContext context = new RequestParamContext();
context.setMethod(request.getMethodValue());
context.setPath(request.getPath().value());
//仅获取 uri 上 query param
//getQueryParams:
//1.get 请求url参数
//2.post 请求url上带的参数
//3.获取不了body 请求参数
Map<String, String> queryParams = request.getQueryParams().toSingleValueMap();
context.setQueryParams(queryParams);
if (contentType != null) {
//如果仅仅只有地址栏上有参数,则contentType为空
context.setContentType(MediaType.toString(Arrays.asList(contentType)));
}
if (context.getMethod().equals(HttpMethod.POST.name()) && headers.getContentLength() > 0) {
return cacheBody(exchange, chain, context);
}
RequestContextUtil.setRequestParamContext(exchange, context);
RequestContextUtil.logRequest(context,log);
return chain.filter(exchange);
}
public Mono<Void> cacheBody(ServerWebExchange exchange, GatewayFilterChain chain, RequestParamContext context) {
return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
//引用+1
DataBufferUtils.retain(dataBuffer);
DataBuffer tmpDataBuffer = dataBuffer.slice(0, dataBuffer.readableByteCount());
byte[] bytes = new byte[tmpDataBuffer.readableByteCount()];
tmpDataBuffer.read(bytes);
// 将复制出来的tmpDataBuffer的计数器减少2,这个的同时也会将原始ataBuffer减少2
String body = new String(bytes, StandardCharsets.UTF_8);
DataBufferUtils.release(tmpDataBuffer);
context.setBody(body);
RequestContextUtil.setRequestParamContext(exchange, context);
RequestContextUtil.logRequest(context, log);
return chain.filter(exchange.mutate().request(decorateRequest(exchange, dataBuffer)).build());
});
}
private ServerHttpRequest decorateRequest(ServerWebExchange exchange, DataBuffer dataBuffer) {
return new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return Flux.just(dataBuffer);
}
};
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE + 100;
}
}
RequestParamContext
@Data
public class RequestParamContext {
/**
* url 上的请求参数,不包含 请求 body 数据
*/
private Map<String, String> queryParams;
/**
* 请求方法
*/
private String method;
/**
* 请求类型
*/
private String contentType;
/**
* body 参数
*
* 1.json:{a:b,c:d}
* 2.xxx-form: a=b&c=d
*
*/
private String body;
/**
* 请求路径,除queryParams
*/
private String path;
}
业务系统 cloud-user
GetController
@RestController
@Slf4j
public class GetController {
@GetMapping("/get")
public String get(GetParam param) {
log.info("param:{}", JSON.toJSONString(param));
return "get";
}
@GetMapping("/get/{id}")
public String get(@PathVariable("id") Integer id, GetParam param) {
param.setId(id);
log.info("param:{}", JSON.toJSONString(param));
return "get";
}
}
PostController
@RestController
@Slf4j
public class PostController {
@PostMapping("/post")
public GetParam post(GetParam param) {
log.info("param:{}", JSON.toJSONString(param));
return param;
}
@PostMapping("/post/{id}")
public GetParam postPath(@PathVariable("id") Integer id, GetParam param) {
param.setId(id);
log.info("param:{}", JSON.toJSONString(param));
return param;
}
@PostMapping("/post/body")
public GetParam postBody(@RequestBody GetParam param) {
log.info("param:{}", JSON.toJSONString(param));
return param;
}
}
GetParam
@Data
public class GetParam {
private String name;
private Integer age;
private Integer id;
}