有时候网关层会根据请求将其转发到不同服务后做聚合数据,但在SCG(SpringCloudGateway)本身的配置项是不支持这么做的,故而需要我们做一定的处理。整个实现思路如下:
首先在filter中通过WebClient将请求转发到不同服务,获取respose,而后将其合并成list,最后再合并到data。
整个流程还是蛮简单的,编写代码时候需要掌握到的知识点只有Mono.zip()。只不过webflux用的人不太多,没什么资料。
自己在网上搜了一圈,好像也没多少人这么干,仅有的几篇文章自己也没跑通,可能也只有笔者我有这么奇怪的需求吧hh。
webclient的用法蛮简单,这里重点关注如何做到聚合返回数据。代码如下:
//这部分代码放到filter中
private Mono<Void> aggregateResponse(ServerWebExchange exchange, List<Mono<Response>> responses) {
Mono<List<Response>> combinedResponse = Mono.zip(responses,
objects -> Arrays.stream(objects)
.map(obj -> (Response) obj)
.collect(Collectors.toList()));
// 处理聚合后的响应数据
return combinedResponse.flatMap(
dataList -> {
// 在这里进行聚合处理,提取"data"字段并封装为一条数据
Response rsp = doAggregateResponse(dataList);
// 将聚合后的数据封装成响应返回
return wrapResponse(excahnge,rsp);
});
}
private Response doAggregateResponse(List<Response> dataList) {
List<String> aggregatedData = new ArrayList<>();
for (Response data : dataList) {
if (data.getData() instanceof String) {
aggregatedData.add((String) data.getData());
} else if (data.getData() instanceof List) {
aggregatedData.addAll((List<String>) data.getData());
}
}
return Response.builder()
.code(200)
.data(aggregatedData)
.message(message.toString())
.build();
}
}
private Mono<Void> wrapResponse(ServerWebExchange excahnge,Response rsp){
byte[] responseBytes = rsp.toString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(responseBytes);
return exchange.getResponse().writeWith(Mono.just(buffer));
}
如若返回字段不是很标准,可以这么处理,合并指定字段,
private Mono<Void> aggregateResponse(
ServerHttpResponse serverHttpResponse, List<Mono<String>> allResponse) {
Mono<String> aggregateResponse;
if (allResponse.size() == 1) {
aggregateResponse = allResponse.get(0);
return aggregateResponse.flatMap(tuple->wrapResponse(serverHttpResponse, tuple));
}
//先转JSonObject,遍历获取data,添加到第一个data里
aggregateResponse = Mono.zip(
allResponse,
responses -> {
Iterator<Object> responsesIter = Arrays.stream(responses).iterator();
Object firstResponse = responsesIter.next();
List<String> datas = new ArrayList<>();
JSONObject response = JSONObject.parseObject(firstResponse.toString());
datas.add(response.get("data").toString());
while (responsesIter.hasNext()){
Object objectTmp = responsesIter.next();
JSONObject responseTmp = JSON.parseObject(objectTmp.toString());
String dataTmp = responseTmp.getString(DATA); ;
datas.add(dataTmp);
}
response.put(DATA,datas);
return response.toJSONString();
});
return aggregateResponse.flatMap(tuple->wrapResponse(serverHttpResponse, tuple));
}
private Mono<Void> wrapResponse( ServerHttpResponse response,String responseBody) {
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] responseBytes = responseBody.getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(responseBytes);
return response.writeWith(Mono.just(buffer));
}