spring cloud gateway中如何读取请求参数

作者:影落离风 时间:2021-08-19 16:19:02 

spring cloud gateway读取请求参数

1. 我的版本:

  • spring-cloud:Hoxton.RELEASE

  • spring-boot:2.2.2.RELEASE

  • spring-cloud-starter-gateway

2. 请求日志


import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
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.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author MinWeikai
* @date 2019-12-20 18:09:39
*/
@Slf4j
@Component
public class LoggerFilter implements GlobalFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String method = request.getMethodValue();

if (HttpMethod.POST.matches(method)) {
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
String bodyString = new String(bytes, StandardCharsets.UTF_8);
logtrace(exchange, bodyString);
exchange.getAttributes().put("POST_BODY", bodyString);
DataBufferUtils.release(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
DataBuffer buffer = exchange.getResponse().bufferFactory()
.wrap(bytes);
return Mono.just(buffer);
});

ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
return chain.filter(exchange.mutate().request(mutatedRequest)
.build());
});
} else if (HttpMethod.GET.matches(method)) {
Map m = request.getQueryParams();
logtrace(exchange, m.toString());
}
return chain.filter(exchange);
}

/**
* 日志信息
*
* @param exchange
* @param param    请求参数
*/
private void logtrace(ServerWebExchange exchange, String param) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
String path = serverHttpRequest.getURI().getPath();
String method = serverHttpRequest.getMethodValue();
String headers = serverHttpRequest.getHeaders().entrySet()
.stream()
.map(entry -> "            " + entry.getKey() + ": [" + String.join(";", entry.getValue()) + "]")
.collect(Collectors.joining("\n"));
log.info("\n" + "----------------             ----------------             ---------------->>\n" +
"HttpMethod : {}\n" +
"Uri        : {}\n" +
"Param      : {}\n" +
"Headers    : \n" +
"{}\n" +
"\"<<----------------             ----------------             ----------------"
, method, path, param, headers);
}

}

3. 测试输出,我这边测试没有问题,日志正常输出

spring cloud gateway中如何读取请求参数

gateway网关转发请求添加参数

在继承AbstractGatewayFilterFactory的过滤器中

GET请求添加参数


// 参考api文档中GatewapFilter中“添加请求参数 * ”:AddRequestParameterGatewayFilterFactory.java

//记录日志
           //logger.info("全局参数处理: {} url:{} 参数:{}",method.toString(),serverHttpRequest.getURI().getRawPath(),newRequestQueryParams.toString());
           // 获取原参数
           URI uri = serverHttpRequest.getURI();
           StringBuilder query = new StringBuilder();
           String originalQuery = uri.getRawQuery();
           if (org.springframework.util.StringUtils.hasText(originalQuery)) {
               query.append(originalQuery);
               if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                   query.append('&');
               }
           }
           // 添加查询参数
           query.append(ServiceConstants.COMMON_PARAMETER_ENTERPRISEID+"="+authenticationVO.getEnterpriseId()
                   +"&"+ServiceConstants.COMMON_PARAMETER_USERID+"="+authenticationVO.getUserId());

// 替换查询参数
           URI newUri = UriComponentsBuilder.fromUri(uri)
                   .replaceQuery(query.toString())
                   .build(true)
                   .toUri();

ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
           return chain.filter(exchange.mutate().request(request).build());

POST请求添加参数


//从请求里获取Post请求体
                   String bodyStr = resolveBodyFromRequest(serverHttpRequest);
                   String userId = "123";
// 这种处理方式,必须保证post请求时,原始post表单必须有数据过来,不然会报错
                   if (StringUtils.isEmpty(bodyStr)) {
                       logger.error("请求异常:{} POST请求必须传递参数", serverHttpRequest.getURI().getRawPath());
                       ServerHttpResponse response = exchange.getResponse();
                       response.setStatusCode(HttpStatus.BAD_REQUEST);
                       return response.setComplete();
                   }
                   //application/x-www-form-urlencoded和application/json才添加参数
                   //其他上传文件之类的,不做参数处理,因为文件流添加参数,文件原格式就会出问题了
                  /* if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)) {
                       // 普通键值对,增加参数
                       bodyStr = String.format(bodyStr+"&%s=%s&%s=%s",ServiceConstants.COMMON_PARAMETER_ENTERPRISEID,authenticationVO.getEnterpriseId()
                               ,ServiceConstants.COMMON_PARAMETER_USERID,authenticationVO.getUserId());
                   }*/
                   // 新增body参数
                   if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)) {
                       JSONObject jsonObject = new JSONObject(bodyStr);
                       jsonObject.put("userId", userId);
                       bodyStr = jsonObject.toString();
                   }
                   //记录日志
                   logger.info("全局参数处理: {} url:{} 参数:{}", method.toString(), serverHttpRequest.getURI().getRawPath(), bodyStr);
                   //下面的将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值
                   URI uri = serverHttpRequest.getURI();
                   URI newUri = UriComponentsBuilder.fromUri(uri).build(true).toUri();
                   ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build();
                   DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
                   Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
                   // 定义新的消息头
                   HttpHeaders headers = new HttpHeaders();
                   headers.putAll(exchange.getRequest().getHeaders());
                   // 添加消息头
//                    headers.set(ServiceConstants.SHIRO_SESSION_PRINCIPALS,GsonUtils.toJson(authenticationVO));
                   // 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
                   int length = bodyStr.getBytes().length;
                   headers.remove(HttpHeaders.CONTENT_LENGTH);
                   headers.setContentLength(length);
                   // 设置CONTENT_TYPE
                   if (StringUtils.isEmpty(contentType)) {
                       headers.set(HttpHeaders.CONTENT_TYPE, contentType);
                   }
                   // 由于post的body只能订阅一次,由于上面代码中已经订阅过一次body。所以要再次封装请求到request才行,不然会报错请求已经订阅过
                   request = new ServerHttpRequestDecorator(request) {
                       @Override
                       public HttpHeaders getHeaders() {
                           long contentLength = headers.getContentLength();
                           HttpHeaders httpHeaders = new HttpHeaders();
                           httpHeaders.putAll(super.getHeaders());
                           if (contentLength > 0) {
                               httpHeaders.setContentLength(contentLength);
                           } else {
                               // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org
                               httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                           }
                           return httpHeaders;
                       }
                       @Override
                       public Flux<DataBuffer> getBody() {
                           return bodyFlux;
                       }
                   };
                   //封装request,传给下一级
                   request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyStr.length()));
                   return chain.filter(exchange.mutate().request(request).build());
  /**
    * 从Flux<DataBuffer>中获取字符串的方法
    * @return 请求体
    */
   private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
       //获取请求体
       Flux<DataBuffer> body = serverHttpRequest.getBody();
       AtomicReference<String> bodyRef = new AtomicReference<>();
       body.subscribe(buffer -> {
           CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
           DataBufferUtils.release(buffer);
           bodyRef.set(charBuffer.toString());
       });
       //获取request body
       return bodyRef.get();
   }

/**
* 字符串转DataBuffer
* @param value
* @return
*/
private DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}

来源:https://blog.csdn.net/weixin_41187876/article/details/103637035

标签:springcloud,gateway,请求,参数
0
投稿

猜你喜欢

  • java自动生成编号的实现(格式:yyMM+四位流水号)

    2023-10-10 09:24:36
  • java实现分页显示效果

    2021-12-29 20:17:43
  • Java实现简易扑克牌游戏的完整实例

    2022-10-08 14:09:18
  • mybatis-plus使用问题小结

    2023-10-30 06:45:58
  • idea中将单个java类导出为jar包文件的方法

    2022-08-18 11:15:55
  • C#模拟实现鼠标自动点击与消息发送功能

    2023-02-09 08:51:14
  • SpringMVC编程使用Controller接口实现控制器实例代码

    2023-02-01 02:03:36
  • 详解在spring boot中消息推送系统设计与实现

    2023-05-28 04:17:00
  • java emoji表情存储的解决方法

    2023-07-10 20:19:06
  • visual studio 2019安装配置可编写c/c++语言的IDE环境

    2023-10-04 02:01:02
  • java 动态生成SQL的实例讲解

    2021-05-25 18:26:06
  • java中functional interface的分类和使用详解

    2021-09-15 15:59:20
  • spring mvc中的@PathVariable获得请求url中的动态参数

    2023-08-22 22:08:40
  • java property配置文件管理工具框架过程详解

    2023-10-12 04:35:50
  • SpringBoot自动装配原理详解

    2023-07-26 08:44:46
  • Java Socket使用加密协议进行传输对象的方法

    2023-11-28 12:47:44
  • Java面向对象程序设计:继承,多态用法实例分析

    2021-08-03 06:54:04
  • 使用maven命令安装jar包到本地仓库的方法步骤

    2022-10-19 21:57:58
  • C# Memcached缓存用法实例详解

    2023-06-29 07:27:33
  • Eureka源码阅读之环境搭建及工程结构

    2023-07-26 01:02:36
  • asp之家 软件编程 m.aspxhome.com