gateway通过GlobalFilter做数据缓存

主要实现,当通过接口请求数据时,先从redis里面查询数据,如果redis里面有数据则直接返回,果如没有数据则请求接口获取数据(我这里redis的key是url,主要是测试用)

参考地址:

https://blog.csdn.net/qq_35387940/article/details/119753044

package com.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.gateway.config.BaseConfig;
import com.gateway.utils.RedisUtil;
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.beans.factory.annotation.Autowired;
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.ServerHttpRequest;
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.StandardCharsets;
import java.util.List;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;

/**
 * 网关跳转过滤类
 *
 * @Author: hans
 * @Date: 2020/05/23
 */
@Component
public class SkipFilter implements GlobalFilter, Ordered {

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

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

    @Autowired
    private BaseConfig baseConfig;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        String url = request.getURI().getPath();

        String data = getDataFromRedis(url);
        if(data != null){
            ServerHttpResponse resp = exchange.getResponse();
            resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
            System.out.println("data: " + data);
            DataBuffer buffer = resp.bufferFactory().wrap(data.getBytes(StandardCharsets.UTF_8));
            return resp.writeWith(Flux.just(buffer));
        }
        System.out.println("url: " + url);
        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);
                            setDataToRedis(url, responseData);
                            byte[] uppedContent = new String(responseData.getBytes(), StandardCharsets.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());
    }

    private String getDataFromRedis(String key){
        Object o = redisUtil.get(key);
        if(o== null){
            return null;
        }
        return o.toString();
    }

    private void setDataToRedis(String key, String data){
        redisUtil.set(key, data, baseConfig.getRedisTimeOut());
    }



    @Override
    public int getOrder() {
        return -999;
    }

    /**
     * 认证错误输出
     *
     * @param resp 响应对象
     * @param mess 错误信息
     * @return
     */
    private Mono<Void> authError(ServerHttpResponse resp, String mess) {
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("message", mess);
        String returnStr = jsonObject.toJSONString();
        DataBuffer buffer = resp.bufferFactory().wrap(returnStr.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }
}
posted on 2022-01-05 16:09  james-roger  阅读(477)  评论(0编辑  收藏  举报