前言

        项目需要在Gateway中获取请求参数,原生提供了request.getQueryParams()方法获取请求参数,但是只能获得url上的param,对于form body中的参数获取不到。找了很多方法,网上普遍都是通过自定义Filter缓存Body中的内容,然后再获取缓存的Body,此处的缓存实现方法各异,有些还存在内存泄漏问题。本文使用官方自带的缓存过滤器实现,然后整合url参数和body参数到同一对象进行查询。

配置官方过滤器

        在yml配置文件中设置CacheRequestBodyGatewayFilterFactory过滤器到请求链路上,此过滤器或帮我们缓存请求中的body,避免后文获取不到body。需要注意的是yml中的name对应的是CacheRequestBody,还需要提供一个bodyClass参数,具体配置看代码。

spring:
  cloud:
    gateway:
      routes:
        #user 模块
        - id: user-system
          uri: lb://user-system
          predicates:
            - Path=/user/**
          filters:
            - name: CacheRequestBody
              args:
                bodyClass: java.lang.String
            # token认证
            - TokenFilter

获取参数

        上文配置缓存后,我们就可以在自定义过滤器中获取body内容了,此处获取到的是String类型的数据,类似:name=123456&sex=1。我们使用自定义方法将body字符串进行解析,然后将原有的queryParams合并到一起方便后文查询。

public class TokenFilter extends AbstractGatewayFilterFactory {

	@Override
	public GatewayFilter apply(Object config) {
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest();
			//获取body内容,必须在yml中配置CacheRequestBody,让系统缓存body,不然此处无法获取
			String cachedRequestBody = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
			MultiValueMap<String, String> queryParams = formatUrlParam(cachedRequestBody, request.getQueryParams());
			// 获取参数
			String grantType = queryParams.getFirst("grant_type");
			// TODO 业务逻辑
			return chain.filter(exchange.mutate().request(request).build());
		};
	}

	/**
	 * 将body中的字符串格式化并合并url中的参数
	 * @param cachedRequestBody body字符串
	 * @return map
	 */
	private MultiValueMap<String, String> formatUrlParam(String cachedRequestBody, MultiValueMap<String, String> queryParams){
		if(cachedRequestBody == null || "".equals(cachedRequestBody.trim())){
			return queryParams;
		}
		//定义返回对象
		Map<String, List<String>> mapParam = new HashMap<>();
		//拷贝url中的参数
		queryParams.forEach(mapParam::put);
		//解析body中的参数
		String[] splitURL=cachedRequestBody.split("&");
		for(String s:splitURL){
			if(s.indexOf("=") > 0){
				s = s.replace("&", "");
				int index = s.indexOf("=");
				String key = s.substring(0, index);
				String value = s.substring(index+1);
				//适配系统逻辑
				List<String> list = mapParam.computeIfAbsent(key, k -> new ArrayList<>());
				list.add(value);
			}
		}
		return new MultiValueMapAdapter<>(mapParam);
	}
}

总结

  1. 配置yml中的CacheRequestBody
  2. 自定义过滤器中获取:
    exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR)
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐