很久没有使用gateway了 偶尔看到大家在问如何获取完整body体,这里放上我的方法。
org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory 中定义 在路由中配置了该谓词 就可以将 body体中的数据放到exchange.getAttribute(“cachedRequestBodyObject”);
我们怎么使用呢?
@Bean
public RouteLocator requestBodyCacheRoute(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
RouteLocatorBuilder.Builder serviceProvider = routes
.route("requestBodyCacheRoute",
r -> r.method(HttpMethod.POST)
.and()
.readBody(String.class, readBody -> true)
.and()
.path(SERVICE)
.uri(URI));
RouteLocator routeLocator = serviceProvider.build();
return routeLocator;
}
该方式能够获取到完整的body体并且不会产生body体被读一次后无法再次读取的问题
使用
String requestBody = exchange.getAttribute("cachedRequestBodyObject");
try {
requestBody = URLDecoder.decode(requestBody, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
即可获取参数
我封装了一个统一处理get post 参数的方法
/**
* @Description 封装ServerWebExchange统一获取参数方法
* @Author changyandong
* @Emoji (゜ - ゜)つ干杯
* @Created Date: 2019/8/27 9:21
* @ClassName ServerWebExchangeUtils
* @Version: 1.0
*/
public abstract class ServerWebExchangeUtils {
public static Map<String, String> getParam(ServerWebExchange exchange) {
HttpMethod method = exchange.getRequest().getMethod();
if (Objects.equals(HttpMethod.GET, method)) {
return handlingGetRequestParam(exchange);
}
return handlingPostRequestParam(exchange);
}
public static Map<String, String> handlingPostRequestParam(ServerWebExchange exchange) {
// 这个属性就是readBody 谓词写入的 完整body体内容
String requestBody = exchange.getAttribute("cachedRequestBodyObject");
try {
requestBody = URLDecoder.decode(requestBody, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String contentType = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
//当 参数为 json
if (Objects.equals(contentType, MediaType.APPLICATION_JSON_VALUE)) {
JSONObject json = JSONObject.parseObject(requestBody);
Map<String, Object> innerMap = json.getInnerMap();
Map<String, String> returnMap = new LinkedHashMap<>();
innerMap.forEach((k, v) -> returnMap.put(k, String.valueOf(v)));
return returnMap;
} else if (Objects.equals(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
String[] params = requestBody.split("&");
Map<String, String> returnMap = new LinkedHashMap<>();
String lastKey = "";
for (int i = 0; i < params.length; i++) {
int index = params[i].indexOf('=');
// 处理 value中含 &的情况
if (index < 0) {
returnMap.put(lastKey, returnMap.get(lastKey) + "&" + params[i]);
continue;
}
// 取第一个=号 后面的都是value
String value = params[i].substring(index + 1);
String key = params[i].substring(0, index);
returnMap.put(key, value);
lastKey = key;
}
return returnMap;
}
return new LinkedHashMap<>();
}
public static Map<String, String> handlingGetRequestParam(ServerWebExchange exchange) {
return exchange.getRequest().getQueryParams().toSingleValueMap();
}
}
具体原理就是我使用一个全局的Route 给他塞了readBody ReadBodyPredicateFactory就会解析 放到
exchange.getAttributes()中。我这个工具类并不全面,大家看个大概,我的工具类适用于我 并不一定适用于所有场景。