完美解决SpringCloud-gateway全局GlobalFilter获取post的请求参数截取导致获取参数不全

我们在使用SpringCloud-gateway作为网关转发的时候,当post请求参数过程,刚好需要针对post请求体做相应的操作时候的,会发现每次获取的请求参数获取不全的问题,以下解决方法,来自于百度总结,实战可用;



@Component
public class DefaulFilter implements GlobalFilter, Ordered {

    public final static String REDIS_KEY_ACCESS_TOKEN_PLATFORM = "PLATFORM_ACCESS_TOKEN#";

    @Value(value = "${platform.publicKey}")
    private String publicKey;

    @Value(value = "${platform.privateKey}")
    private String privateKey;

    @Autowired
    @Qualifier(value = "excludeRequestMap")
    private Map<String, String> excludeRequestMap;

    private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();

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

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest serverHttpRequest= exchange.getRequest();
        // 符合条件请求直接放行:1.swagger文档请求接口  2.相关的登录请求接口
        if (excludeRequestMap.containsKey(serverHttpRequest.getURI().getPath())
                || HttpMethod.GET.equals(serverHttpRequest.getMethod())) {
            return chain.filter(exchange.mutate().request(exchange.getRequest()).build());
        }
        //判断是否为post请求
        if (HttpMethod.POST.equals(serverHttpRequest.getMethod())) {
            return processRequest(exchange, chain);
        }else if (HttpMethod.GET.equals(serverHttpRequest.getMethod())) {
            //1 判断是否为get请求
            return chain.filter(exchange);
        }
        return chain.filter(exchange);
    }

    private Mono<Void> processRequest(ServerWebExchange exchange, GatewayFilterChain chain) {
        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);
        //从head中获取敏感信息--机密后的json字符串
        HttpHeaders headers = exchange.getRequest().getHeaders();
        String platformEnExchangeInfo = headers.getFirst(LogFilterConstants.PLATFORM_EXCHANGE_INFO);
        SensitiveInfoView sensitiveInfoView=new SensitiveInfoView();
        //通过私钥解密获取解密后敏感信息-加密信息不为空
        if(StringUtils.isNotBlank(platformEnExchangeInfo)) {
            try {
                PrivateKey privateKeyEntity = RsaUtils.getPrivateKey(privateKey);
                String platformDeExchangeInfo = RsaUtils.decrypt(platformEnExchangeInfo, privateKeyEntity);
                //转换成json对象
                JSONObject jsonObject = JSONObject.parseObject(platformDeExchangeInfo);
                sensitiveInfoView = JSON.toJavaObject(jsonObject, SensitiveInfoView.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //把用户信息压入token中
        Map<String, Object> claimsMap = new HashMap<>();
//      claimsMap.put(LogFilterConstants.SENSITIVE_INFO_KEY, sensitiveInfoView);
        claimsMap.put("CLAIM_NAME_ID_NO",sensitiveInfoView.getIdNo());
        String newToken = JwtUtils.createAccessToken(sensitiveInfoView.getMobileNumber(),claimsMap, 1000);

        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
        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);
                JSONObject newBodyStr = JSONObject.parseObject(text);
                newBodyStr.put("token", newToken);
                text=newBodyStr.toJSONString();
                DataBuffer data = bufferFactory.allocateBuffer();
                data.write(text.getBytes(StandardCharsets.UTF_8));
                holder.dataBuffer = data;
            });
            ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {

                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.putAll(super.getHeaders());
                    //由于修改了请求体的body,导致content-length长度不确定,因此使用分块编码
                    httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                    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 class DataBufferHolder {
        DataBuffer dataBuffer;
        int length;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan4609

整理不易,谢谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值