0

在我通过 SpringCloud-Gateway 修改 requestBody 和 responseBody 后,我发送了请求,它第一次返回了“200”的状态码。

在此处输入图像描述

但是当我再次发送这个请求时,它返回了“400 bad request”!

在此处输入图像描述

我尝试了很多次,但这种情况仍然存在。相关类如下。

RequestEncryptionGlobalFilter.java

package com.jovian.gateway.filter;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.jovian.gateway.api.CommonResult;
import com.jovian.gateway.constant.CacheConstant;
import com.jovian.gateway.constant.CommonConstant;
import com.jovian.gateway.service.ServerLogService;
import com.jovian.gateway.uitl.JwtUtil;
import com.jovian.gateway.uitl.RedisUtil;
import com.jovian.gateway.uitl.oConvertUtils;
import com.jovian.gateway.vo.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.cloud.gateway.support.DefaultServerRequest;
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.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author h
 * @date 2021/10/12
 */
@Slf4j
@Component
public class RequestEncryptionGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ServerLogService serverLogService;
    private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
    @Autowired
    private RedisUtil redisUtil;
    @Override
    public int getOrder() {
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        return chain.filter(exchange);

        return processRequest(exchange, chain);
    }

    private Mono<Void> processRequest(ServerWebExchange exchange, GatewayFilterChain chain) {
        //CA

        ServerHttpRequest request = exchange.getRequest();

        
        ServerLog serverLog = new ServerLog();
        serverLog.setCreateBy("admin");
        serverLog.setCreateTime(LocalDateTime.now());
        serverLog.setRequestTime(DateUtil.now());
        serverLog.setRequestIp(oConvertUtils.getIpAddrByRequest(request));

        String token = exchange.getRequest().getHeaders().getFirst("X-Access-Token");
        if(!checkUserTokenIsEffect(token,serverLog)){
            ServerHttpResponse baseExchange = exchange.getResponse();
            baseExchange.setStatusCode(HttpStatus.OK);
            baseExchange.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            String body= JSONUtil.toJsonStr(CommonResult.unauthorized("errorMessage1"));
            DataBuffer buffer = baseExchange.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
            return baseExchange.writeWith(Mono.just(buffer));
        }
        RequestPath path = request.getPath();
        serverLog.setServerResourceId(path.toString());
        serverLogService.saveOrUpdate(serverLog);
        exchange.getRequest().mutate().header("logId", serverLog.getId()).build();
        
        ServerRequest serverRequest = new DefaultServerRequest(exchange, messageReaders);
        DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
        Mono<String> rawBody = serverRequest.bodyToMono(String.class).map(s -> s);
        BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(rawBody, String.class);
        HttpHeaders tempHeaders = new HttpHeaders();
        tempHeaders.putAll(exchange.getRequest().getHeaders());
        tempHeaders.remove(HttpHeaders.CONTENT_LENGTH);
        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, tempHeaders);
        return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
            Flux<DataBuffer> body = outputMessage.getBody();
            DataBufferHolder holder = new DataBufferHolder();
            body.subscribe(dataBuffer -> {
                int len = dataBuffer.readableByteCount();
                holder.length = len;
                byte[] bytes = new byte[len];
                dataBuffer.read(bytes);
                DataBufferUtils.release(dataBuffer);
                String text = new String(bytes, StandardCharsets.UTF_8);
                log.info("text:{}",text);
                JsonNode jsonNode = readNode(text);
                DataBuffer data = bufferFactory.allocateBuffer();
                serverLog.setRequestParam(text);
                serverLogService.saveOrUpdate(serverLog);
                data.write(jsonNode.toString().getBytes(StandardCharsets.UTF_8));
                holder.dataBuffer = data;
            });
            ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {

                @Override
                public HttpHeaders getHeaders() {
                    long contentLength = tempHeaders.getContentLength();
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.putAll(super.getHeaders());
                    if (contentLength > 0) {
                        httpHeaders.setContentLength(contentLength);
                    } else {
                        httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                    }
                    return httpHeaders;
                }

                @Override
                public Flux<DataBuffer> getBody() {
                    return Flux.just(holder.dataBuffer);
                }
            };
            return chain.filter(exchange.mutate().request(requestDecorator).build());
        }));
    }

    private void rewritePayloadNode(String text, JsonNode root) {
        try {
            JsonNode node = objectMapper.readTree(text);
            ObjectNode objectNode = (ObjectNode) root;
            objectNode.set("payload", node);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private void setPayloadTextNode(String text, JsonNode root) {
        try {
            ObjectNode objectNode = (ObjectNode) root;
            objectNode.set("payload", new TextNode(text));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private JsonNode readNode(String in) {
        try {
            return objectMapper.readTree(in);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private class DataBufferHolder {

        DataBuffer dataBuffer;
        int length;
    }


    public Boolean checkUserTokenIsEffect(String token,ServerLog serverLog)  {
        if (StrUtil.isBlank(token)){
            return false;
        }
        
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            return false;
        }

        
        ArrayList loginUsers = (ArrayList) redisUtil.get(CacheConstant.SYS_USERS_CACHE_JWT + ":" + token);
        if(loginUsers==null||loginUsers.size()==0){
            return false;
        }
        LoginUser loginUser = BeanUtil.mapToBean((Map<?, ?>) loginUsers.get(1),LoginUser.class,true) ;


        if (loginUser.getStatus() != 1) {
            return false;
        }

        if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
            return false;
        }
        serverLog.setUserId(loginUser.getId());

        return true;
    }

    public boolean jwtTokenRefresh(String token, String userName, String passWord) {
        String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
        if (StrUtil.isNotBlank(cacheToken)) {
   
            if (!JwtUtil.verify(cacheToken, userName, passWord)) {
                String newAuthorization = JwtUtil.sign(userName, passWord);

                redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
                redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME *2 / 1000);

            }


            return true;
        }
        return false;
    }
}

ResponseDecryptionGlobalFilter.java

package com.jovian.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.jovian.gateway.api.CommonResult;
import com.jovian.gateway.service.ServerLogService;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.cloud.gateway.support.DefaultClientResponse;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;

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

/**
 * @author h
 * @date 2021/10/12
 */
@Slf4j
@Component
public class ResponseDecryptionGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private ServerLogService serverLogService;
    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return processResponse(exchange, chain);
    }

    private Mono<Void> processResponse(ServerWebExchange exchange, GatewayFilterChain chain) {
        String logId = exchange.getRequest().getHeaders().getFirst("logId");
        ServerLog serverLog = new ServerLog();
        serverLog.setId(logId);
        log.info(logId);
        ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType);
                ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders);
                DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
                Mono<String> rawBody = clientResponse.bodyToMono(String.class).map(s -> s);
                BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(rawBody, String.class);
                CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());
                return bodyInserter.insert(outputMessage, new BodyInserterContext())
                        .then(Mono.defer(() -> {
                            Flux<DataBuffer> messageBody = outputMessage.getBody();
                            Flux<DataBuffer> flux = messageBody.map(buffer -> {
                                CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
                                DataBufferUtils.release(buffer);
                                JsonNode jsonNode = readNode(charBuffer.toString());
                                String text = jsonNode.toString();
                                serverLog.setResponseData(text);
                                serverLog.setResponseStatus(getStatusCode().toString());
                                serverLogService.saveOrUpdate(serverLog);
                                JSONObject jsonObject = JSONUtil.parseObj(text);
                                CommonResult<JSONObject> success = CommonResult.success(jsonObject);
                                String s = JSONUtil.toJsonStr(success);

                                return getDelegate().bufferFactory().wrap(s.getBytes(StandardCharsets.UTF_8));
                            });
                            HttpHeaders headers = getDelegate().getHeaders();
                            if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
                                flux = flux.doOnNext(data -> headers.setContentLength(data.readableByteCount()));
                            }
                            return getDelegate().writeWith(flux);
                        }));
            }
        };
        return chain.filter(exchange.mutate().response(responseDecorator).build());
    }

    private void setPayloadTextNode(String text, JsonNode root) {
        try {
            ObjectNode objectNode = (ObjectNode) root;
            objectNode.set("payload", new TextNode(text));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private JsonNode readNode(String in) {
        try {
            return objectMapper.readTree(in);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private class ResponseAdapter implements ClientHttpResponse {

        private final Flux<DataBuffer> flux;
        private final HttpHeaders headers;

        @SuppressWarnings("unchecked")
        private ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {
            this.headers = headers;
            if (body instanceof Flux) {
                flux = (Flux) body;
            } else {
                flux = ((Mono) body).flux();
            }
        }

        @Override
        public Flux<DataBuffer> getBody() {
            return flux;
        }

        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }

        @Override
        public HttpStatus getStatusCode() {
            return null;
        }

        @Override
        public int getRawStatusCode() {
            return 0;
        }

        @Override
        public MultiValueMap<String, ResponseCookie> getCookies() {
            return null;
        }
    }
}
4

0 回答 0