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

打印 上一主题 下一主题

主题 890|帖子 890|积分 2680

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

  • 通过Filter过滤器
  • 通过Predicate断言
原理都类似,通过事先缓存doby到attribute中,再读取。至于这两种区别主要在于缓存方式:filter直接加一层globalFilter即可,而Predicate则需要加一个配置项。具体请看代码
配置Filter获取
  1. import lombok.NonNull;  
  2. import lombok.extern.slf4j.Slf4j;  
  3. import org.springframework.cloud.gateway.filter.GatewayFilterChain;  
  4. import org.springframework.cloud.gateway.filter.GlobalFilter;  
  5. import org.springframework.core.Ordered;  
  6. import org.springframework.core.io.buffer.DataBuffer;  
  7. import org.springframework.core.io.buffer.DataBufferUtils;  
  8. import org.springframework.http.server.reactive.ServerHttpRequest;  
  9. import org.springframework.http.server.reactive.ServerHttpRequestDecorator;  
  10. import org.springframework.stereotype.Component;  
  11. import org.springframework.web.server.ServerWebExchange;  
  12. import reactor.core.publisher.Flux;  
  13. import reactor.core.publisher.Mono;  
  14.    
  15. @Component  
  16. public class ReadParamFilter implements GlobalFilter, Ordered {  
  17.   
  18.     @Override  
  19.     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {  
  20.         if (exchange.getRequest().getHeaders().getContentType() == null) {  
  21.             return chain.filter(exchange);  
  22.         } else {  
  23.             return DataBufferUtils.join(exchange.getRequest().getBody())  
  24.                     .flatMap(dataBuffer -> {  
  25.                         DataBufferUtils.retain(dataBuffer);  
  26.                         Flux<DataBuffer> cachedFlux = Flux  
  27.                                 .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));  
  28.                         ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {  
  29.                             @Override  
  30.                             public @NonNull Flux<DataBuffer> getBody() {  
  31.                                 return cachedFlux;  
  32.                             }  
  33.   
  34.                         };  
  35.                         exchange.getAttributes().put("cachedRequestBodyObject", cachedFlux);   
  36.                     });  
  37.         }  
  38.     }  
  39.   
  40.     @Override  
  41.     public int getOrder() {  
  42.         return Ordered.HIGHEST_PRECEDENCE;  
  43.     }  
  44. }
复制代码
缺点:在断言阶段不能获取参数
配置Predicate获取

predicate缓存request body需要加一个配置项
  1. spring:  
  2.   cloud:  
  3.     gateway:  
  4.       predicate:  
  5.         read-body:  
  6.           enabled: true
复制代码
另外再加一个读取body的Predicate类。
  1. ## 断言类
  2. ```java
  3. @Component  
  4. public class BodyPredicate implements Predicate {  
  5.    @Override  
  6.    public boolean test(Object o) {  
  7.       return true;  
  8.    }  
  9. }
复制代码
缓存到之后,后边获取参数就比较方便了。
获取参数
  1. @Service  
  2. public class ParamFactory {  
  3.    @Autowired  
  4.    Map<String, ParamStrategy> getParamFactoryMap;  
  5.   
  6.    public ParamStrategy getParamStrategy(HttpMethod requestMethod){  
  7.       return getParamFactoryMap.get(requestMethod.name());  
  8.    }  
  9. }
复制代码
获取参数策略
  1. public abstract class ParamStrategy {  
  2.   
  3.     public RequestParamBO analyzeRequestParam(ServerWebExchange exchange) {  
  4.         return doAnalyzeRequestParam(exchange);  
  5.     }  
  6.   
  7.     /**  
  8.      * 解析请求数据  
  9.      *  
  10.      * @param exchange  
  11.     * @return  
  12.      */  
  13.     protected abstract RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange);  
  14.   
  15.     /**  
  16.      * 获取某个请求参数  
  17.      *  
  18.      * @param requestMessage  
  19.      * @param paramKey  
  20.      * @param position  
  21.      * @return  
  22.      */  
  23.     public abstract String getParamValue(RequestMessageBO requestMessage, String paramKey,  
  24.                                          String position);  
  25.   
  26.   
  27. }
复制代码
get
  1. @Component("GET")  
  2. public class GetParamStrategy extends ParamStrategy {  
  3.   
  4.     /**  
  5.      * 解析请求数据  
  6.      *  
  7.      * @param exchange@return  
  8.      */    @Override  
  9.     protected RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange) {  
  10.         Map<String, String> paramMap = new HashMap<>();  
  11.         MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();  
  12.         if (!queryParams.isEmpty()) {  
  13.             paramMap =  
  14.                     queryParams.entrySet().stream()  
  15.                             .collect(  
  16.                                     Collectors.toMap(  
  17.                                             Map.Entry::getKey,  
  18.                                             entry -> {  
  19.                                                 List<String> list =  
  20.                                                         new ArrayList<>(entry.getValue());  
  21.                                                 // list包含空数据  
  22.                                                 list.removeIf(Objects::isNull);  
  23.                                                 if (list.size() != 0) {  
  24.                                                     return entry.getValue().get(0);  
  25.                                                 } else {  
  26.                                                     return "";  
  27.                                                 }  
  28.                                             }));  
  29.         }  
  30.         return RequestParamBO.builder()  
  31.                 .queryParams(paramMap)  
  32.                 .build();  
  33.     }  
  34.   
  35.     @Override  
  36.     public String getParamValue(RequestMessageBO requestMessage, String paramKey, String position) {  
  37.         Map<String,String> queryParam = requestMessage.getParam().getQueryParams();  
  38.         if (CollectionUtils.isEmpty(queryParam)){  
  39.             return null;  
  40.         }  
  41.         return queryParam.get(paramKey);  
  42.     }  
  43. }
复制代码
post
  1. @Component("POST")  
  2. public class PostParamStrategy extends ParamStrategy {  
  3.   
  4.     private static final String XW_FORM_PARAM_REGEX = "&";  
  5.     private static final String XW_KEY_VALUE_REGEX = "=";  
  6.   
  7.     /**  
  8.      * 解析请求数据  
  9.      *  
  10.      * @param exchange  
  11.      * @return  
  12.      */  
  13.     @Override  
  14.     protected RequestParamBO doAnalyzeRequestParam(ServerWebExchange exchange) {  
  15.         Map<String, String> paramMap = new HashMap<>();  
  16.         Map<String, Object> attributes = exchange.getAttributes();  
  17.         MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();  
  18.         RequestParamBO requestParams = new RequestParamBO();  
  19.         if (CollectionUtil.isNotEmpty(queryParams)) {  
  20.             paramMap =  
  21.                     queryParams.entrySet().stream()  
  22.                             .collect(  
  23.                                     Collectors.toMap(  
  24.                                             Map.Entry::getKey,  
  25.                                             entry -> {  
  26.                                                 List<String> list =  
  27.                                                         new ArrayList<>(entry.getValue());  
  28.                                                 // list包含空数据  
  29.                                                 list.removeIf(Objects::isNull);  
  30.                                                 if (list.size() != 0) {  
  31.                                                     return entry.getValue().get(0);  
  32.                                                 } else {  
  33.                                                     return "";  
  34.                                                 }  
  35.                                             }));  
  36.         }  
  37.         requestParams.setQueryParams(paramMap);  
  38.         MediaType contentType = exchange.getRequest().getHeaders().getContentType();  
  39.         String body = (String) attributes.get(CACHE_REQUEST_BODY_OBJECT);  
  40.   
  41.         if (MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {  
  42.             assert contentType != null;  
  43.             requestParams.setFormParams(getFormParam(contentType.toString(), body));  
  44.         } else if (APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {  
  45.             requestParams.setFormParams(getXwFormParam(body));  
  46.         } else if (APPLICATION_JSON.isCompatibleWith(contentType)) {  
  47.             //json body就直接作为String处理保存了,
  48.             requestParams.setJsonBody(body);  
  49.         }  
  50.   
  51.         return requestParams;  
  52.     }  
  53.   
  54.     @Override  
  55.     public String getParamValue(RequestMessageBO requestMessage, String paramKey, String position) {  
  56.         MediaType mediaType = requestMessage.getMediaType();  
  57.         if (APPLICATION_JSON.isCompatibleWith(mediaType)) {  
  58.             Object document = Configuration.defaultConfiguration()  
  59.                     .jsonProvider().parse(requestMessage.getParam().getJsonBody());  
  60.             JSONArray paramValues = Objects.requireNonNull(JsonPath.read(document, position));  
  61.             return String.valueOf(paramValues.get(0));  
  62.         }else {  
  63.             return requestMessage.getParam().getFormParams().get(paramKey);  
  64.         }  
  65.     }  
  66.   
  67.    //获取 表单数据
  68.   
  69.     @SneakyThrows  
  70.     private Map<String, String> getFormParam(String contentType, String bodyString) {  
  71.   
  72.         String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);  
  73.         Map<String, String> formMap = Maps.newHashMap();  
  74.         String part =  
  75.                 "^\r\nContent-Disposition: form-data; name="([^/?]+)"\r\n\r\n([^/?]+)\r\n--?$";  
  76.         Pattern r = Pattern.compile(part);  
  77.         String[] split = bodyString.split(boundary);  
  78.         for (int x = 1; x < split.length - 1; x++) {  
  79.             Matcher m = r.matcher(split[x]);  
  80.             if (m.find()) {  
  81.                 String name = m.group(1);  
  82.                 String value = m.group(2);  
  83.                 formMap.put(name, value);  
  84.             }  
  85.         }  
  86.         return formMap;  
  87.     }  
  88.   //获取xw表单数据
  89.     private Map<String, String> getXwFormParam(String bodyStr) {  
  90.         Map<String, String> paramMap = new HashMap<>();  
  91.         try {  
  92.             bodyStr = URLDecoder.decode(bodyStr, "utf-8");  
  93.         } catch (UnsupportedEncodingException e) {  
  94.             throw new RuntimeException(e);  
  95.         }  
  96.         String[] params = bodyStr.split(XW_FORM_PARAM_REGEX);  
  97.         for (String paramKeyValue : params) {  
  98.             String[] keyValue = paramKeyValue.split(XW_KEY_VALUE_REGEX);  
  99.             if (keyValue.length == 2) {  
  100.                 paramMap.put(keyValue[0], keyValue[1]);  
  101.             }  
  102.         }  
  103.         return paramMap;  
  104.     }
  105. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表