天天看點

SpringCloud GateWay 網關 在GlobalFilter 拿出傳回資料response前言正文  

前言

文章主旨:   将傳回資料拿出來,然後各種處理。

正文

先看該篇文章的示例接口:

SpringCloud GateWay 網關 在GlobalFilter 拿出傳回資料response前言正文  

紅色框框裡面就是傳回的 response 資料 。

現在我們想要的就是 在傳回給到調用方(前端、第三方等)前,我們抓出來資料,随便改一下東西。

例如: 我要把裡面的message 提示語改了。

建立一個全局過濾器:

WrapperResponseGlobalFilter.java

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
import java.util.List;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;

/**
 * @Author JCccc
 * @Description 攔截傳回資料, 修改傳回資料
 * @Date 2021/8/16 19:22
 */

@Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(WrapperResponseGlobalFilter.class);

    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }

    private static Joiner joiner = Joiner.on("");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    // 擷取ContentType,判斷是否傳回JSON格式資料
                    String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                    if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                        //(傳回資料内如果字元串過大,預設會切割)解決傳回體分段傳輸
                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            List<String> list = Lists.newArrayList();
                            dataBuffers.forEach(dataBuffer -> {
                                try {
                                    byte[] content = new byte[dataBuffer.readableByteCount()];
                                    dataBuffer.read(content);
                                    DataBufferUtils.release(dataBuffer);
                                    list.add(new String(content, "utf-8"));
                                } catch (Exception e) {
                                    log.info("加載Response位元組流異常,失敗原因:{}", Throwables.getStackTraceAsString(e));
                                }
                            });
                            String responseData = joiner.join(list);

                            
                            System.out.println("responseData:"+responseData);

                            
                            byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
                            originalResponse.getHeaders().setContentLength(uppedContent.length);
                            return bufferFactory.wrap(uppedContent);
                        }));
                    }
                }
                return super.writeWith(body);
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };
        return chain.filter(exchange.mutate().response(response).build());
    }


}
           

調用接口可以看到,response資料已經被我們拎出來了:

SpringCloud GateWay 網關 在GlobalFilter 拿出傳回資料response前言正文  

那麼我們簡單做個處理,

SpringCloud GateWay 網關 在GlobalFilter 拿出傳回資料response前言正文  
/**
     * 傳回資料處理
     *
     * @param responseData
     * @return
     */
    private String responseHandle(String responseData) {
        String responseResultJson = null;
        try {
            JSONObject jsonObject = JSONObject.parseObject(responseData);
            jsonObject.put("message", "JCccc 收藏+關注");
            responseResultJson = jsonObject.toJSONString();
        } catch (Exception e) {
            log.info("傳回資料處理轉化失敗,異常資訊={}",e.getMessage());
            return responseData;
        }
        return responseResultJson;
    }
           

再次請求,可以看到:

傳回資料裡面的message已經被我們修改成功了

SpringCloud GateWay 網關 在GlobalFilter 拿出傳回資料response前言正文  

PS:

還有類似,既然個人資訊這麼敏感,是不是類似一些接口傳回資料需要做統一的加密呢? 

如需要,那麼也可以通過配置化讀取需要加密的ur清單,然後通過exchange把url拿出來做匹對,對responseData  做加密處理。

ServerHttpRequest request = exchange.getRequest();

URI url = request.getURI();

String urlPath = url.getPath();

System.out.println("目前請求url是:"+urlPath);

好了,該篇就到這。

繼續閱讀