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[x]);
- 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[0], keyValue[1]);
- }
- }
- return paramMap;
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |