Only one connection receive subscriber allowed.

这个filter 中报Only one connection receive subscriber allowed.

主要是body体为null的情况

@Component
public class DecryptionFilter implements GlobalFilter, Ordered {

@SneakyThrows
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

解决办法:
在这里插入图片描述
参考:https://blog.csdn.net/weixin_37644979/article/details/115264027

完全代码:

package com.riocento.filter;


import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBufAllocator;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
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.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Iterator;

/**
 * 解密过滤器
 * 对请求的request进行解密
 */
@Slf4j
@Component
public class DecryptionFilter implements GlobalFilter, Ordered {

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("request解密处理");
        //源request对象
        ServerHttpRequest request = exchange.getRequest();
        //获取请求方式
        HttpMethod method = request.getMethod();
        URI uri = request.getURI();
        log.info("请求方式:"+method);
        log.info("请求地址:"+uri);
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        log.info("所有参数:"+queryParams);
        //是否为加密参数
        Boolean isEncrypt = false;
        // GET请求解密
        if(HttpMethod.GET == method){
            if(queryParams.containsKey("isEncrypt")){
                isEncrypt = Boolean.valueOf(queryParams.get("isEncrypt").get(0));
            }
            if(isEncrypt){
                //加密参数
                String enParams = queryParams.get("enParams").get(0);
                //将参数解密
                String paramsStr = AESUtil.decrypt(enParams);
                //格式化参数
                String urlParams = formatUrlParams(paramsStr);
                //重新创建request
                URI plaintUrl = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), urlParams, uri.getFragment());
                ServerHttpRequest newRequest = request.mutate().uri(plaintUrl).build();
                return chain.filter(exchange.mutate().request(newRequest).build());
            }
        }
        //POST和PUT请求解密
        else if(HttpMethod.POST == method
                || HttpMethod.PUT == method) {
            if(queryParams.containsKey("isEncrypt")){
                isEncrypt = Boolean.valueOf(queryParams.get("isEncrypt").get(0));
            }
            if(isEncrypt){
                URI plaintUrl = null;
                //处理url参数
                if(queryParams.size() > 0 && queryParams.containsKey("enParams")){
                    //加密参数
                    String urlEnParams = queryParams.get("enParams").get(0);
                    //将参数解密
                    String urlParamsStr = AESUtil.decrypt(urlEnParams);
                    //格式化参数
                    String urlParams = formatUrlParams(urlParamsStr);
                    //重新创建uri
                    plaintUrl = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), urlParams, uri.getFragment());
                }else{
                    plaintUrl = uri;
                }

                //处理表单参数
                //获取表单信息
                Flux<DataBuffer> dataBufferFlux = request.getBody();
                //获取body中的数据
                String strBody = FilterRequestResponseUtil.resolveBodyFromRequest(dataBufferFlux);
                //获取加密参数
                String enParams = getEnParams(strBody);
                //将参数解密
                String paramsStr = AESUtil.decrypt(enParams);

                ServerHttpRequest newRequest = request.mutate().uri(plaintUrl).build();
                DataBuffer bodyDataBuffer = stringBuffer(paramsStr);
                if(paramsStr == null) {
                    newRequest = new ServerHttpRequestDecorator(newRequest) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return Flux.just(bodyDataBuffer);
                        }
                    };
                    // 构建新的请求头
                    HttpHeaders headers = new HttpHeaders();
                    headers.putAll(exchange.getRequest().getHeaders());
                    // 重新设置CONTENT_LENGTH
                    int length = 0;
                    headers.remove(HttpHeaders.CONTENT_LENGTH);
                    headers.setContentLength(length);
                    newRequest = new ServerHttpRequestDecorator(newRequest) {
                        @Override
                        public HttpHeaders getHeaders() {
                            return headers;
                        }
                    };
                    return chain.filter(exchange.mutate().request(newRequest).build());
                }
                Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
                newRequest = new ServerHttpRequestDecorator(newRequest) {
                    @Override
                    public Flux<DataBuffer> getBody() {
                        return bodyFlux;
                    }
                };
                // 构建新的请求头
                HttpHeaders headers = new HttpHeaders();
                headers.putAll(exchange.getRequest().getHeaders());
                // 重新设置CONTENT_LENGTH
                int length = paramsStr.getBytes().length;
                headers.remove(HttpHeaders.CONTENT_LENGTH);
                headers.setContentLength(length);
                newRequest = new ServerHttpRequestDecorator(newRequest) {
                    @Override
                    public HttpHeaders getHeaders() {
                        return headers;
                    }
                };
                return chain.filter(exchange.mutate().request(newRequest).build());
            }
        }
        //DELETE等请求方式不做处理
        return chain.filter(exchange);
    }

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

    /**
     * 格式化url参数
     * @param paramsStr 字符串参数
     */
    private String formatUrlParams(String paramsStr){
        StringBuilder stbResult = new StringBuilder();
        if(Strings.isNotEmpty(paramsStr)){
            if(paramsStr.startsWith("{")){
                JSONObject paramsJSON = JSONObject.parseObject(paramsStr);
                Iterator<String> iterator = paramsJSON.keySet().iterator();
                while (iterator.hasNext()) {
                    String key = iterator.next();
                    String value = paramsJSON.getString(key);
                    if(stbResult.length() > 0){
                        stbResult.append("&");
                    }
                    stbResult.append(key).append("=").append(value);
                }
            }else{
                stbResult.append(paramsStr);
            }
        }

        return stbResult.toString();
    }

    /**
     * 获取加密字符串参数
     * @return
     */
    private String getEnParams(String paramsStr){
        String result = null;
        if(Strings.isNotEmpty(paramsStr)){
            if(paramsStr.startsWith("{")){
                //将字符串转换为JSON格式
                JSONObject jsonBody = JSONObject.parseObject(paramsStr);
                result = jsonBody.getString("enParams");
            }else if(paramsStr.indexOf("=") > 0){
                String[] paramsArr = paramsStr.split("=");
                result = paramsArr[1];
            }
        }
        return  result;
    }

    private DataBuffer stringBuffer(String value) {
        if(value == null) {
            NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
            DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(0);
            return buffer;
        }
        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
        buffer.write(bytes);
        return buffer;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.bolt.gateway.config; import com.bolt.gateway.handler.HystrixFallbackHandler; import com.bolt.gateway.props.AuthProperties; import com.bolt.gateway.props.RouteProperties; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.cors.reactive.CorsUtils; import org.springframework.web.filter.reactive.HiddenHttpMethodFilter; import org.springframework.web.reactive.function.server.RequestPredicates; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; /** * 路由配置信息 * * @author arch_group */ @Slf4j @Configuration @AllArgsConstructor @EnableConfigurationProperties({RouteProperties.class, AuthProperties.class}) public class RouterFunctionConfiguration { /** * 这里为支持的请求头,如果有自定义的header字段请自己添加 */ private static final String ALLOWED_HEADERS = "x-requested-with, zkpt-ks-auth, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client"; private static final String ALLOWED_METHODS = "*"; private static final String ALLOWED_ORIGIN = "*"; private static final String ALLOWED_EXPOSE = "*"; private static final String MAX_AGE = "18000L"; private final HystrixFallbackHandler hystrixFallbackHandler; @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { ServerHttpResponse response = ctx.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS); headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS); headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN); headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE); headers.add("Access-Control-Max-Age", MAX_AGE); headers.add("Access-Control-Allow-Credentials", "true"); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } @Bean public RouterFunction routerFunction() { return RouterFunctions.route( RequestPredicates.path("/fallback") .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), hystrixFallbackHandler); } /** * 解决springboot2.0.5版本出现的 Only one connection receive subscriber allowed. * 参考:https://github.com/spring-cloud/spring-cloud-gateway/issues/541 */ @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter() { return new HiddenHttpMethodFilter() { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange); } }; } }
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值