泉缘泉 发表于 2024-2-11 12:48:32

Spring Cloud Gateway实践(一):获取参数

SCG(Spring Cloud Gateway)就我个人理解,是想让开发者把它作为一个较为简单的网关框架,只需简单在yml文件中写几个配置项就可以运行。所以它不大推荐在网关这一层获取body数据或者做一下复杂的业务处理。故而在实际编写代码中,获取queryParam很容易,但body数据就比较麻烦了,如果要修改就更麻烦。在本篇文章主要讨论如何获取请求方式中的参数。
SCG获取参数一般有两种方式:

[*]通过Filter过滤器
[*]通过Predicate断言
原理都类似,通过事先缓存doby到attribute中,再读取。至于这两种区别主要在于缓存方式:filter直接加一层globalFilter即可,而Predicate则需要加一个配置项。具体请看代码
配置Filter获取

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
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.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
   
@Component
public class ReadParamFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      if (exchange.getRequest().getHeaders().getContentType() == null) {
            return chain.filter(exchange);
      } else {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                  .flatMap(dataBuffer -> {
                        DataBufferUtils.retain(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux
                              .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                            @Override
                            public @NonNull Flux<DataBuffer> getBody() {
                              return cachedFlux;
                            }

                        };
                        exchange.getAttributes().put("cachedRequestBodyObject", cachedFlux);   
                  });
      }
    }

    @Override
    public int getOrder() {
      return Ordered.HIGHEST_PRECEDENCE;
    }
}缺点:在断言阶段不能获取参数
配置Predicate获取

predicate缓存request body需要加一个配置项
spring:
cloud:
    gateway:
      predicate:
      read-body:
          enabled: true 另外再加一个读取body的Predicate类。
## 断言类

```java
@Component
public class BodyPredicate implements Predicate {
   @Override
   public boolean test(Object o) {
      return true;
   }
}缓存到之后,后边获取参数就比较方便了。
获取参数

@Service
public class ParamFactory {
   @Autowired
   Map<String, ParamStrategy> getParamFactoryMap;

   public ParamStrategy getParamStrategy(HttpMethod requestMethod){
      return getParamFactoryMap.get(requestMethod.name());
   }
}获取参数策略

public abstract class ParamStrategy {

    public RequestParamBO analyzeRequestParam(ServerWebExchange exchange) {
      return doAnalyzeRequestParam(exchange);
    }

    /**
   * 解析请求数据
   *
   * @param exchange
    * @return
   */
    protected abstract RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange);

    /**
   * 获取某个请求参数
   *
   * @param requestMessage
   * @param paramKey
   * @param position
   * @return
   */
    public abstract String getParamValue(RequestMessageBO requestMessage, String paramKey,
                                       String position);


}get

@Component("GET")
public class GetParamStrategy extends ParamStrategy {

    /**
   * 解析请求数据
   *
   * @param exchange@return
   */    @Override
    protected RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange) {
      Map<String, String> paramMap = new HashMap<>();
      MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
      if (!queryParams.isEmpty()) {
            paramMap =
                  queryParams.entrySet().stream()
                            .collect(
                                    Collectors.toMap(
                                          Map.Entry::getKey,
                                          entry -> {
                                                List<String> list =
                                                      new ArrayList<>(entry.getValue());
                                                // list包含空数据
                                                list.removeIf(Objects::isNull);
                                                if (list.size() != 0) {
                                                    return entry.getValue().get(0);
                                                } else {
                                                    return "";
                                                }
                                          }));
      }
      return RequestParamBO.builder()
                .queryParams(paramMap)
                .build();
    }

    @Override
    public String getParamValue(RequestMessageBO requestMessage, String paramKey, String position) {
      Map<String,String> queryParam = requestMessage.getParam().getQueryParams();
      if (CollectionUtils.isEmpty(queryParam)){
            return null;
      }
      return queryParam.get(paramKey);
    }

}post

@Component("POST")
public class PostParamStrategy extends ParamStrategy {

    private static final String XW_FORM_PARAM_REGEX = "&";
    private static final String XW_KEY_VALUE_REGEX = "=";

    /**
   * 解析请求数据
   *
   * @param exchange
   * @return
   */
    @Override
    protected RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange) {
      Map<String, String> paramMap = new HashMap<>();
      Map<String, Object> attributes = exchange.getAttributes();
      MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
      RequestParamBO requestParams = new RequestParamBO();
      if (CollectionUtil.isNotEmpty(queryParams)) {
            paramMap =
                  queryParams.entrySet().stream()
                            .collect(
                                    Collectors.toMap(
                                          Map.Entry::getKey,
                                          entry -> {
                                                List<String> list =
                                                      new ArrayList<>(entry.getValue());
                                                // list包含空数据
                                                list.removeIf(Objects::isNull);
                                                if (list.size() != 0) {
                                                    return entry.getValue().get(0);
                                                } else {
                                                    return "";
                                                }
                                          }));
      }
      requestParams.setQueryParams(paramMap);
      MediaType contentType = exchange.getRequest().getHeaders().getContentType();
      String body = (String) attributes.get(CACHE_REQUEST_BODY_OBJECT);

      if (MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
            assert contentType != null;
            requestParams.setFormParams(getFormParam(contentType.toString(), body));
      } else if (APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
            requestParams.setFormParams(getXwFormParam(body));
      } else if (APPLICATION_JSON.isCompatibleWith(contentType)) {
            //json body就直接作为String处理保存了,
            requestParams.setJsonBody(body);
      }

      return requestParams;
    }

    @Override
    public String getParamValue(RequestMessageBO requestMessage, String paramKey, String position) {
      MediaType mediaType = requestMessage.getMediaType();
      if (APPLICATION_JSON.isCompatibleWith(mediaType)) {
            Object document = Configuration.defaultConfiguration()
                  .jsonProvider().parse(requestMessage.getParam().getJsonBody());
            JSONArray paramValues = Objects.requireNonNull(JsonPath.read(document, position));
            return String.valueOf(paramValues.get(0));
      }else {
            return requestMessage.getParam().getFormParams().get(paramKey);
      }
    }

   //获取 表单数据

    @SneakyThrows
    private Map<String, String> getFormParam(String contentType, String bodyString) {

      String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);
      Map<String, String> formMap = Maps.newHashMap();
      String part =
                "^\r\nContent-Disposition: form-data; name=\"([^/?]+)\"\r\n\r\n([^/?]+)\r\n--?$";
      Pattern r = Pattern.compile(part);
      String[] split = bodyString.split(boundary);
      for (int x = 1; x < split.length - 1; x++) {
            Matcher m = r.matcher(split);
            if (m.find()) {
                String name = m.group(1);
                String value = m.group(2);
                formMap.put(name, value);
            }
      }
      return formMap;
    }
//获取xw表单数据
    private Map<String, String> getXwFormParam(String bodyStr) {
      Map<String, String> paramMap = new HashMap<>();
      try {
            bodyStr = URLDecoder.decode(bodyStr, "utf-8");
      } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
      }
      String[] params = bodyStr.split(XW_FORM_PARAM_REGEX);
      for (String paramKeyValue : params) {
            String[] keyValue = paramKeyValue.split(XW_KEY_VALUE_REGEX);
            if (keyValue.length == 2) {
                paramMap.put(keyValue, keyValue);
            }
      }
      return paramMap;
    }
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Spring Cloud Gateway实践(一):获取参数