Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
promotion-gateway
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
promotion
promotion-gateway
Commits
41e46741
提交
41e46741
authored
5月 30, 2024
作者:
000516
提交者:
Coding
5月 30, 2024
浏览文件
操作
浏览文件
下载
差异文件
日志格式整理,登录人id放到header
Merge Request: 日志格式整理,登录人id放到header Created By: @李秋林 Accepted By: @李秋林 URL:
https://g-pkkp8204.coding.net/p/promotion/d/promotion-gateway/git/merge/36?initial=true
上级
f355bb35
f190edcd
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
439 行增加
和
158 行删除
+439
-158
CorsConfig.java
src/main/java/com/promotion/gateway/CorsConfig.java
+49
-0
UserDataServiceImpl.java
.../com/promotion/gateway/data/impl/UserDataServiceImpl.java
+0
-3
AuthGlobalFilter.java
...n/java/com/promotion/gateway/filter/AuthGlobalFilter.java
+9
-55
WrapperResponseGlobalFilter.java
...promotion/gateway/filter/WrapperResponseGlobalFilter.java
+86
-100
MyCachedBodyOutputMessage.java
...omotion/gateway/filter/log/MyCachedBodyOutputMessage.java
+58
-0
RequestLogFilter.java
...va/com/promotion/gateway/filter/log/RequestLogFilter.java
+198
-0
SysLog.java
src/main/java/com/promotion/gateway/filter/log/SysLog.java
+39
-0
没有找到文件。
src/main/java/com/promotion/gateway/CorsConfig.java
0 → 100644
浏览文件 @
41e46741
package
com
.
promotion
.
gateway
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpMethod
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.web.cors.reactive.CorsUtils
;
import
org.springframework.web.server.ServerWebExchange
;
import
org.springframework.web.server.WebFilter
;
import
org.springframework.web.server.WebFilterChain
;
import
reactor.core.publisher.Mono
;
/**
* @author John
* @date 2022/6/27
* @description 跨域配置
*/
@Configuration
public
class
CorsConfig
{
@Bean
public
WebFilter
corsFilter
()
{
return
(
ServerWebExchange
ctx
,
WebFilterChain
chain
)
->
{
ServerHttpRequest
request
=
ctx
.
getRequest
();
if
(
CorsUtils
.
isCorsRequest
(
request
))
{
HttpHeaders
requestHeaders
=
request
.
getHeaders
();
ServerHttpResponse
response
=
ctx
.
getResponse
();
HttpMethod
requestMethod
=
requestHeaders
.
getAccessControlRequestMethod
();
HttpHeaders
headers
=
response
.
getHeaders
();
headers
.
add
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_ORIGIN
,
requestHeaders
.
getOrigin
());
headers
.
addAll
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_HEADERS
,
requestHeaders
.
getAccessControlRequestHeaders
());
if
(
requestMethod
!=
null
)
{
headers
.
add
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_METHODS
,
requestMethod
.
name
());
}
headers
.
add
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_CREDENTIALS
,
"true"
);
headers
.
add
(
HttpHeaders
.
ACCESS_CONTROL_EXPOSE_HEADERS
,
"*"
);
if
(
request
.
getMethod
()
==
HttpMethod
.
OPTIONS
)
{
response
.
setStatusCode
(
HttpStatus
.
OK
);
return
Mono
.
empty
();
}
}
return
chain
.
filter
(
ctx
);
};
}
}
\ No newline at end of file
src/main/java/com/promotion/gateway/data/impl/UserDataServiceImpl.java
浏览文件 @
41e46741
...
...
@@ -22,9 +22,6 @@ public class UserDataServiceImpl implements UserDataService {
@Override
public
JSONObject
getUserByToken
(
String
token
)
{
ValueOperations
<
String
,
String
>
vo
=
redisTemplate
.
opsForValue
();
String
val
=
vo
.
get
(
token
);
return
JSONObject
.
parseObject
(
val
);
...
...
src/main/java/com/promotion/gateway/filter/AuthGlobalFilter.java
浏览文件 @
41e46741
...
...
@@ -13,19 +13,14 @@ import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URI
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Arrays
;
import
java.util.List
;
...
...
@@ -40,7 +35,10 @@ import java.util.Objects;
@Component
public
class
AuthGlobalFilter
implements
GlobalFilter
,
Ordered
{
// 用户注册、用户登录、发送手机号验证码
/**
* 放行URL
* 用户注册、用户登录、发送手机号验证码
*/
private
final
List
<
String
>
whiteUrls
=
Arrays
.
asList
(
"/login"
,
"/enroll"
,
"/sms/send/ver_code"
);
@Autowired
...
...
@@ -48,68 +46,29 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
long
millis
=
System
.
currentTimeMillis
();
ServerHttpRequest
request
=
exchange
.
getRequest
();
URI
URIPath
=
request
.
getURI
();
String
method
=
request
.
getMethodValue
();
HttpHeaders
header
=
request
.
getHeaders
();
log
.
info
(
"------------- 开始 -------------"
);
log
.
info
(
"\n请求request信息:\nURI : {}\nheader = {}"
,
URIPath
,
header
);
String
url
=
exchange
.
getRequest
().
getURI
().
getPath
();
// 1、判断url是否放行
boolean
isIgnore
=
whiteUrls
.
stream
().
anyMatch
(
url:
:
contains
);
if
(
isIgnore
)
{
log
.
info
(
"
请求放行,URL
:{}"
,
url
);
log
.
info
(
"
非校验URL放行
:{}"
,
url
);
return
chain
.
filter
(
exchange
);
}
String
token
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
// 2、未登录请求跳转登录
String
token
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
if
(
StringUtils
.
isBlank
(
token
))
{
return
loginError
(
exchange
);
}
// 3、验证token
'
// 3、验证token
JSONObject
userJson
=
userDataService
.
getUserByToken
(
RedisKeys
.
UserKeys
.
TEMPORARY_TOKEN
.
getKey
()
+
token
);
if
(
Objects
.
isNull
(
userJson
))
{
log
.
info
(
"token登录错误:{}"
,
token
);
return
loginError
(
exchange
);
}
if
(
"POST"
.
equals
(
method
))
{
return
DataBufferUtils
.
join
(
exchange
.
getRequest
().
getBody
())
.
flatMap
(
dataBuffer
->
{
byte
[]
bytes
=
new
byte
[
dataBuffer
.
readableByteCount
()];
dataBuffer
.
read
(
bytes
);
try
{
String
bodyString
=
new
String
(
bytes
,
"utf-8"
);
log
.
info
(
"\n请求参数:\n"
+
bodyString
);
exchange
.
getAttributes
().
put
(
"POST_BODY"
,
bodyString
);
}
catch
(
UnsupportedEncodingException
e
)
{
e
.
printStackTrace
();
}
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
;
}
};
log
.
info
(
"------------- 结束-------------"
,
System
.
currentTimeMillis
()
-
millis
);
return
chain
.
filter
(
exchange
.
mutate
().
request
(
mutatedRequest
)
.
build
());
});
}
return
chain
.
filter
(
exchange
);
ServerHttpRequest
httpRequest
=
exchange
.
getRequest
().
mutate
().
header
(
"loginId"
,
userJson
.
getString
(
"id"
)).
header
(
"loginQcId"
,
userJson
.
getString
(
"qcId"
)).
build
();
return
chain
.
filter
(
exchange
.
mutate
().
request
(
httpRequest
).
build
());
}
@Override
...
...
@@ -123,12 +82,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
response
.
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
R
res
=
new
R
(
RCode
.
NOT_LOGIN_ERROR
);
DataBuffer
buffer
=
response
.
bufferFactory
().
wrap
(
new
Gson
().
toJson
(
res
).
getBytes
(
StandardCharsets
.
UTF_8
));
log
.
info
(
"------------- 结束 -------------"
);
return
response
.
writeWith
(
Flux
.
just
(
buffer
));
}
private
void
logSave
()
{
}
}
src/main/java/com/promotion/gateway/filter/WrapperResponseGlobalFilter.java
浏览文件 @
41e46741
package
com
.
promotion
.
gateway
.
filter
;
import
com.alibaba.fastjson.JSONObject
;
import
com.baomidou.mybatisplus.core.toolkit.StringUtils
;
import
com.wangxiaolu.promotion.common.redis.RedisKeys
;
import
io.netty.util.internal.StringUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.reactivestreams.Publisher
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferFactory
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.DefaultDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.http.server.reactive.ServerHttpResponseDecorator
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URI
;
import
java.nio.charset.Charset
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Objects
;
/**
* @author : liqiulin
* @date : 2024-05-24 15
* @describe :
*/
@Component
@Slf4j
public
class
WrapperResponseGlobalFilter
implements
GlobalFilter
,
Ordered
{
@Override
public
int
getOrder
()
{
//-1 is response write filter, must be called before that
return
-
2
;
}
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
//获取response的 返回数据
ServerHttpResponse
originalResponse
=
exchange
.
getResponse
();
DataBufferFactory
bufferFactory
=
originalResponse
.
bufferFactory
();
ServerHttpResponseDecorator
decoratedResponse
=
new
ServerHttpResponseDecorator
(
originalResponse
)
{
@Override
public
Mono
<
Void
>
writeWith
(
Publisher
<?
extends
DataBuffer
>
body
)
{
if
(
getStatusCode
().
equals
(
HttpStatus
.
OK
)
&&
body
instanceof
Flux
)
{
Flux
<?
extends
DataBuffer
>
fluxBody
=
Flux
.
from
(
body
);
// return super.writeWith(fluxBody.map(dataBuffer -> {
return
super
.
writeWith
(
fluxBody
.
buffer
().
map
(
dataBuffer
->
{
//如果响应过大,会进行截断,出现乱码,然后看api DefaultDataBufferFactory有个join方法可以合并所有的流,乱码的问题解决
DataBufferFactory
dataBufferFactory
=
new
DefaultDataBufferFactory
();
DataBuffer
join
=
dataBufferFactory
.
join
(
dataBuffer
);
byte
[]
content
=
new
byte
[
join
.
readableByteCount
()];
join
.
read
(
content
);
//释放掉内存
DataBufferUtils
.
release
(
join
);
//打印响应日志
log
.
info
(
"------------- 返回信息 -------------"
);
log
.
info
(
new
String
(
content
,
StandardCharsets
.
UTF_8
));
log
.
info
(
"------------- 返回信息 -------------"
);
return
bufferFactory
.
wrap
(
content
);
// byte[] content = new byte[dataBuffer.readableByteCount()];
// dataBuffer.read(content);
//package com.promotion.gateway.filter;
//
//
//import com.alibaba.fastjson.JSONObject;
//import com.baomidou.mybatisplus.core.toolkit.StringUtils;
//import com.wangxiaolu.promotion.common.redis.RedisKeys;
//import io.netty.util.internal.StringUtil;
//import lombok.extern.slf4j.Slf4j;
//import org.reactivestreams.Publisher;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
//import org.springframework.core.Ordered;
//import org.springframework.core.io.buffer.DataBuffer;
//import org.springframework.core.io.buffer.DataBufferFactory;
//import org.springframework.core.io.buffer.DataBufferUtils;
//import org.springframework.core.io.buffer.DefaultDataBufferFactory;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.server.reactive.ServerHttpRequest;
//import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
//import org.springframework.http.server.reactive.ServerHttpResponse;
//import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
//import org.springframework.stereotype.Component;
//import org.springframework.web.server.ServerWebExchange;
//import reactor.core.publisher.Flux;
//import reactor.core.publisher.Mono;
//
//import java.io.UnsupportedEncodingException;
//import java.net.URI;
//import java.nio.charset.Charset;
//import java.nio.charset.StandardCharsets;
//import java.util.Objects;
//
///**
// * @author : liqiulin
// * @date : 2024-05-24 15
// * @describe :
// */
//
//@Component
//@Slf4j
//public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
//
// @Override
// public int getOrder() {
// //-1 is response write filter, must be called before that
// return -2;
// }
//
// @Override
// public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// //获取response的 返回数据
// ServerHttpResponse originalResponse = exchange.getResponse();
// DataBufferFactory bufferFactory = originalResponse.bufferFactory();
// ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
// @Override
// public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
// if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
// Flux<? extends DataBuffer> fluxBody = Flux.from(body);
//
// return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
// //如果响应过大,会进行截断,出现乱码,然后看api DefaultDataBufferFactory有个join方法可以合并所有的流,乱码的问题解决
// DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
// DataBuffer join = dataBufferFactory.join(dataBuffer);
// byte[] content = new byte[join.readableByteCount()];
// join.read(content);
// //释放掉内存
// DataBufferUtils.release(
dataBuffer
);
//
//resultContent就是下游系统返回的内容,可以查看修改
//
String responseData = new String(content, Charset.forName("UTF-8"));
// DataBufferUtils.release(
join
);
//
//
//打印响应日志
// log.info("------------- 返回信息 -------------");
// log.info(
responseData
);
// log.info(
new String(content, StandardCharsets.UTF_8)
);
// log.info("------------- 返回信息 -------------");
// byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
// return bufferFactory.wrap(uppedContent);
}));
}
else
{
log
.
error
(
"响应code异常:{}"
,
getStatusCode
());
}
return
super
.
writeWith
(
body
);
}
};
return
chain
.
filter
(
exchange
.
mutate
().
response
(
decoratedResponse
).
build
());
}
}
\ No newline at end of file
// return bufferFactory.wrap(content);
// }));
// } else {
// log.error("响应code异常:{}", getStatusCode());
// }
// return super.writeWith(body);
// }
// };
// return chain.filter(exchange.mutate().
//
// response(decoratedResponse).
//
// build());
// }
//}
\ No newline at end of file
src/main/java/com/promotion/gateway/filter/log/MyCachedBodyOutputMessage.java
0 → 100644
浏览文件 @
41e46741
package
com
.
promotion
.
gateway
.
filter
.
log
;
import
org.reactivestreams.Publisher
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.ReactiveHttpOutputMessage
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.util.function.Supplier
;
public
class
MyCachedBodyOutputMessage
implements
ReactiveHttpOutputMessage
{
private
final
DataBufferFactory
bufferFactory
;
private
final
HttpHeaders
httpHeaders
;
private
Flux
<
DataBuffer
>
body
=
Flux
.
error
(
new
IllegalStateException
(
"The body is not set. Did handling complete with success?"
));
public
MyCachedBodyOutputMessage
(
ServerWebExchange
exchange
,
HttpHeaders
httpHeaders
)
{
this
.
bufferFactory
=
exchange
.
getResponse
().
bufferFactory
();
this
.
httpHeaders
=
httpHeaders
;
}
public
void
beforeCommit
(
Supplier
<?
extends
Mono
<
Void
>>
action
)
{
}
public
boolean
isCommitted
()
{
return
false
;
}
public
HttpHeaders
getHeaders
()
{
return
this
.
httpHeaders
;
}
public
DataBufferFactory
bufferFactory
()
{
return
this
.
bufferFactory
;
}
public
Flux
<
DataBuffer
>
getBody
()
{
return
this
.
body
;
}
public
Mono
<
Void
>
writeWith
(
Publisher
<?
extends
DataBuffer
>
body
)
{
this
.
body
=
Flux
.
from
(
body
);
return
Mono
.
empty
();
}
public
Mono
<
Void
>
writeAndFlushWith
(
Publisher
<?
extends
Publisher
<?
extends
DataBuffer
>>
body
)
{
return
this
.
writeWith
(
Flux
.
from
(
body
).
flatMap
((
p
)
->
{
return
p
;
}));
}
public
Mono
<
Void
>
setComplete
()
{
return
this
.
writeWith
(
Flux
.
empty
());
}
}
src/main/java/com/promotion/gateway/filter/log/RequestLogFilter.java
0 → 100644
浏览文件 @
41e46741
package
com
.
promotion
.
gateway
.
filter
.
log
;
import
cn.hutool.core.util.ObjectUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.reactivestreams.Publisher
;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.cloud.gateway.route.Route
;
import
org.springframework.cloud.gateway.support.BodyInserterContext
;
import
org.springframework.cloud.gateway.support.ServerWebExchangeUtils
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
import
org.springframework.core.io.buffer.DataBufferFactory
;
import
org.springframework.core.io.buffer.DataBufferUtils
;
import
org.springframework.core.io.buffer.DefaultDataBufferFactory
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.codec.HttpMessageReader
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.http.server.reactive.ServerHttpResponseDecorator
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.web.reactive.function.BodyInserter
;
import
org.springframework.web.reactive.function.BodyInserters
;
import
org.springframework.web.reactive.function.server.HandlerStrategies
;
import
org.springframework.web.reactive.function.server.ServerRequest
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Map
;
/**
* @author John
* @date 2022/6/20
* @description 日志过滤器
*/
@Slf4j
@Component
public
class
RequestLogFilter
implements
GlobalFilter
,
Ordered
{
private
final
List
<
HttpMessageReader
<?>>
messageReaders
=
HandlerStrategies
.
withDefaults
().
messageReaders
();
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
HttpHeaders
headers
=
request
.
getHeaders
();
//请求路径
String
requestUrl
=
request
.
getPath
().
pathWithinApplication
().
value
();
Route
route
=
exchange
.
getAttribute
(
ServerWebExchangeUtils
.
GATEWAY_ROUTE_ATTR
);
SysLog
sysLog
=
new
SysLog
().
setSchema
(
request
.
getURI
().
getScheme
())
.
setRequestMethod
(
request
.
getMethodValue
())
.
setRequestPath
(
requestUrl
)
.
setTargetServer
(
route
.
getId
())
.
setRequestTime
(
new
Date
())
.
setToken
(
headers
.
getFirst
(
"Authorization"
));
MediaType
mediaType
=
headers
.
getContentType
();
if
(
MediaType
.
APPLICATION_JSON
.
isCompatibleWith
(
mediaType
))
{
return
printBodyLog
(
exchange
,
chain
,
sysLog
);
}
else
{
return
printBasicLog
(
exchange
,
chain
,
sysLog
);
}
}
private
Mono
<
Void
>
printBasicLog
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
,
SysLog
sysLog
)
{
StringBuilder
builder
=
new
StringBuilder
();
MultiValueMap
<
String
,
String
>
queryParams
=
exchange
.
getRequest
().
getQueryParams
();
for
(
Map
.
Entry
<
String
,
List
<
String
>>
entry
:
queryParams
.
entrySet
())
{
builder
.
append
(
entry
.
getKey
()).
append
(
"="
).
append
(
StringUtils
.
join
(
entry
.
getValue
(),
","
));
}
sysLog
.
setRequestBody
(
builder
.
toString
());
//获取响应体
ServerHttpResponseDecorator
decoratedResponse
=
this
.
printResponseLog
(
exchange
,
sysLog
);
return
chain
.
filter
(
exchange
.
mutate
().
response
(
decoratedResponse
).
build
())
.
then
(
Mono
.
fromRunnable
(()
->
{
// 打印日志
this
.
printLog
(
sysLog
);
}));
}
private
Mono
printBodyLog
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
,
SysLog
sysLog
)
{
ServerRequest
serverRequest
=
ServerRequest
.
create
(
exchange
,
messageReaders
);
Mono
<
String
>
modifiedBody
=
serverRequest
.
bodyToMono
(
String
.
class
)
.
flatMap
(
body
->
{
sysLog
.
setRequestBody
(
body
);
return
Mono
.
just
(
body
);
});
// 通过 BodyInserter 插入 body(支持修改body), 避免 request body 只能获取一次
BodyInserter
bodyInserter
=
BodyInserters
.
fromPublisher
(
modifiedBody
,
String
.
class
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
putAll
(
exchange
.
getRequest
().
getHeaders
());
// the new content type will be computed by bodyInserter
// and then set in the request decorator
headers
.
remove
(
HttpHeaders
.
CONTENT_LENGTH
);
MyCachedBodyOutputMessage
outputMessage
=
new
MyCachedBodyOutputMessage
(
exchange
,
headers
);
return
bodyInserter
.
insert
(
outputMessage
,
new
BodyInserterContext
())
.
then
(
Mono
.
defer
(()
->
{
// 重新封装请求
ServerHttpRequest
decoratedRequest
=
requestDecorate
(
exchange
,
headers
,
outputMessage
);
// 记录响应日志
ServerHttpResponseDecorator
decoratedResponse
=
printResponseLog
(
exchange
,
sysLog
);
// 记录普通的
return
chain
.
filter
(
exchange
.
mutate
().
request
(
decoratedRequest
).
response
(
decoratedResponse
).
build
())
.
then
(
Mono
.
fromRunnable
(()
->
{
// 打印日志
printLog
(
sysLog
);
}));
}));
}
private
ServerHttpRequest
requestDecorate
(
ServerWebExchange
exchange
,
HttpHeaders
headers
,
MyCachedBodyOutputMessage
outputMessage
)
{
return
new
ServerHttpRequestDecorator
(
exchange
.
getRequest
())
{
@Override
public
HttpHeaders
getHeaders
()
{
long
contentLength
=
headers
.
getContentLength
();
HttpHeaders
httpHeaders
=
new
HttpHeaders
();
httpHeaders
.
putAll
(
super
.
getHeaders
());
if
(
contentLength
>
0
)
{
httpHeaders
.
setContentLength
(
contentLength
);
}
else
{
httpHeaders
.
set
(
HttpHeaders
.
TRANSFER_ENCODING
,
"chunked"
);
}
return
httpHeaders
;
}
@Override
public
Flux
<
DataBuffer
>
getBody
()
{
return
outputMessage
.
getBody
();
}
};
}
private
ServerHttpResponseDecorator
printResponseLog
(
ServerWebExchange
exchange
,
SysLog
sysLog
)
{
ServerHttpResponse
response
=
exchange
.
getResponse
();
DataBufferFactory
bufferFactory
=
response
.
bufferFactory
();
return
new
ServerHttpResponseDecorator
(
response
)
{
@Override
public
Mono
<
Void
>
writeWith
(
Publisher
<?
extends
DataBuffer
>
body
)
{
if
(
body
instanceof
Flux
)
{
Date
responseTime
=
new
Date
();
sysLog
.
setResponseTime
(
responseTime
);
// 计算执行时间
long
executeTime
=
(
responseTime
.
getTime
()
-
sysLog
.
getRequestTime
().
getTime
());
sysLog
.
setExecuteTime
(
executeTime
);
// 获取响应类型,如果是 json 就打印
String
originalResponseContentType
=
exchange
.
getAttribute
(
ServerWebExchangeUtils
.
ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR
);
if
(
ObjectUtil
.
equal
(
this
.
getStatusCode
(),
HttpStatus
.
OK
)
&&
StringUtils
.
isNotBlank
(
originalResponseContentType
)
&&
originalResponseContentType
.
contains
(
"application/json"
))
{
Flux
<?
extends
DataBuffer
>
fluxBody
=
Flux
.
from
(
body
);
return
super
.
writeWith
(
fluxBody
.
buffer
().
map
(
dataBuffers
->
{
// 合并多个流集合,解决返回体分段传输
DataBufferFactory
dataBufferFactory
=
new
DefaultDataBufferFactory
();
DataBuffer
join
=
dataBufferFactory
.
join
(
dataBuffers
);
byte
[]
content
=
new
byte
[
join
.
readableByteCount
()];
join
.
read
(
content
);
// 释放掉内存
DataBufferUtils
.
release
(
join
);
String
responseResult
=
new
String
(
content
,
StandardCharsets
.
UTF_8
);
sysLog
.
setResponseData
(
responseResult
);
return
bufferFactory
.
wrap
(
content
);
}));
}
}
// if body is not a flux. never got there.
return
super
.
writeWith
(
body
);
}
};
}
private
void
printLog
(
SysLog
sysLog
)
{
log
.
info
(
"------------ 请求响应 start ------------"
);
log
.
info
(
"目标服务:{}:[{}]{}"
,
sysLog
.
getRequestMethod
(),
sysLog
.
getTargetServer
(),
sysLog
.
getRequestPath
());
log
.
info
(
"登录token:{}"
,
sysLog
.
getToken
());
log
.
info
(
"请求参数:{}"
,
sysLog
.
getRequestBody
());
log
.
info
(
"响应信息:{}"
,
sysLog
.
getResponseData
());
log
.
info
(
"------------ 请求结束 {} end ------------"
,
sysLog
.
getExecuteTime
());
// log.info("全局日志:" + sysLog);
}
@Override
public
int
getOrder
()
{
return
-
100
;
}
}
src/main/java/com/promotion/gateway/filter/log/SysLog.java
0 → 100644
浏览文件 @
41e46741
package
com
.
promotion
.
gateway
.
filter
.
log
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
lombok.experimental.Accessors
;
import
java.io.Serializable
;
import
java.util.Date
;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors
(
chain
=
true
)
public
class
SysLog
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
4173350480097599017L
;
private
String
targetServer
;
private
String
requestPath
;
private
String
requestMethod
;
private
String
schema
;
private
String
requestBody
;
private
String
responseData
;
private
String
ip
;
private
Date
requestTime
;
private
Date
responseTime
;
private
Long
executeTime
;
private
String
token
;
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论