spring cloud gateway讀取請求參數(shù)
1. 我的版本:
- spring-cloud:Hoxton.RELEASE
- spring-boot:2.2.2.RELEASE
- spring-cloud-starter-gateway
2. 請求日志
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
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 請求參數(shù) */ 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. 測試輸出,我這邊測試沒有問題,日志正常輸出
gateway網(wǎng)關(guān)轉(zhuǎn)發(fā)請求添加參數(shù)
在繼承AbstractGatewayFilterFactory的過濾器中
GET請求添加參數(shù)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 參考api文檔中GatewapFilter中“添加請求參數(shù)攔截器”:AddRequestParameterGatewayFilterFactory.java //記錄日志 //logger.info("全局參數(shù)處理: {} url:{} 參數(shù):{}",method.toString(),serverHttpRequest.getURI().getRawPath(),newRequestQueryParams.toString()); // 獲取原參數(shù) 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( '&' ); } } // 添加查詢參數(shù) query.append(ServiceConstants.COMMON_PARAMETER_ENTERPRISEID+ "=" +authenticationVO.getEnterpriseId() + "&" +ServiceConstants.COMMON_PARAMETER_USERID+ "=" +authenticationVO.getUserId()); // 替換查詢參數(shù) 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請求添加參數(shù)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//從請求里獲取Post請求體 String bodyStr = resolveBodyFromRequest(serverHttpRequest); String userId = "123" ; // 這種處理方式,必須保證post請求時,原始post表單必須有數(shù)據(jù)過來,不然會報錯 if (StringUtils.isEmpty(bodyStr)) { logger.error( "請求異常:{} POST請求必須傳遞參數(shù)" , serverHttpRequest.getURI().getRawPath()); ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.BAD_REQUEST); return response.setComplete(); } //application/x-www-form-urlencoded和application/json才添加參數(shù) //其他上傳文件之類的,不做參數(shù)處理,因為文件流添加參數(shù),文件原格式就會出問題了 /* if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType)) { // 普通鍵值對,增加參數(shù) bodyStr = String.format(bodyStr+"&%s=%s&%s=%s",ServiceConstants.COMMON_PARAMETER_ENTERPRISEID,authenticationVO.getEnterpriseId() ,ServiceConstants.COMMON_PARAMETER_USERID,authenticationVO.getUserId()); }*/ // 新增body參數(shù) if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)) { JSONObject jsonObject = new JSONObject(bodyStr); jsonObject.put("userId", userId); bodyStr = jsonObject.toString(); } //記錄日志 logger.info("全局參數(shù)處理: {} url:{} 參數(shù):{}", method.toString(), serverHttpRequest.getURI().getRawPath(), bodyStr); //下面的將請求體再次封裝寫回到request里,傳到下一級,否則,由于請求體已被消費,后續(xù)的服務(wù)將取不到值 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)); // 由于修改了傳遞參數(shù),需要重新設(shè)置CONTENT_LENGTH,長度是字節(jié)長度,不是字符串長度 int length = bodyStr.getBytes().length; headers.remove(HttpHeaders.CONTENT_LENGTH); headers.setContentLength(length); // 設(shè)置CONTENT_TYPE if (StringUtils.isEmpty(contentType)) { headers.set(HttpHeaders.CONTENT_TYPE, contentType); } // 由于post的body只能訂閱一次,由于上面代碼中已經(jīng)訂閱過一次body。所以要再次封裝請求到request才行,不然會報錯請求已經(jīng)訂閱過 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(); } |
1
2
3
4
5
6
7
8
9
10
11
12
|
/** * 字符串轉(zhuǎn)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; } |
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/weixin_41187876/article/details/103637035