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

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@Componentpublic class LoggerFilter implements GlobalFilter { @Override public Mono 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 cachedFlux = Flux.defer(() -> {DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes); return Mono.just(buffer); }); ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic Flux 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|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 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_TYPEif (StringUtils.isEmpty(contentType)) {headers.set(HttpHeaders.CONTENT_TYPE, contentType); }// 由于post的body只能订阅一次,由于上面代码中已经订阅过一次body。所以要再次封装请求到request才行,不然会报错请求已经订阅过request = new ServerHttpRequestDecorator(request) {@Overridepublic 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.orghttpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); }return httpHeaders; }@Overridepublic Flux getBody() {return bodyFlux; }}; //封装request,传给下一级request.mutate().header(HttpHeaders.CONTENT_LENGTH, Integer.toString(bodyStr.length())); return chain.filter(exchange.mutate().request(request).build()); /*** 从Flux中获取字符串的方法* @return 请求体*/private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {//获取请求体Flux body = serverHttpRequest.getBody(); AtomicReference bodyRef = new AtomicReference<>(); body.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); DataBufferUtils.release(buffer); bodyRef.set(charBuffer.toString()); }); //获取request bodyreturn 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; }

【spring|spring cloud gateway中如何读取请求参数】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    推荐阅读