SpringCloudGateway实践(二):转发聚合

148 阅读2分钟

有时候网关层会根据请求将其转发到不同服务后做聚合数据,但在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));  
}