Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
P
promotion-gateway
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
promotion
promotion-gateway
Commits
26fbe23d
提交
26fbe23d
authored
5月 30, 2024
作者:
李秋林
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
修改日志打印格式;根据token获取登录人id放到header中;
上级
aa5805b5
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
613 行增加
和
158 行删除
+613
-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
+213
-0
没有找到文件。
src/main/java/com/promotion/gateway/CorsConfig.java
0 → 100644
浏览文件 @
26fbe23d
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
浏览文件 @
26fbe23d
...
@@ -22,9 +22,6 @@ public class UserDataServiceImpl implements UserDataService {
...
@@ -22,9 +22,6 @@ public class UserDataServiceImpl implements UserDataService {
@Override
@Override
public
JSONObject
getUserByToken
(
String
token
)
{
public
JSONObject
getUserByToken
(
String
token
)
{
ValueOperations
<
String
,
String
>
vo
=
redisTemplate
.
opsForValue
();
ValueOperations
<
String
,
String
>
vo
=
redisTemplate
.
opsForValue
();
String
val
=
vo
.
get
(
token
);
String
val
=
vo
.
get
(
token
);
return
JSONObject
.
parseObject
(
val
);
return
JSONObject
.
parseObject
(
val
);
...
...
src/main/java/com/promotion/gateway/filter/AuthGlobalFilter.java
浏览文件 @
26fbe23d
...
@@ -13,19 +13,14 @@ import org.springframework.cloud.gateway.filter.GatewayFilterChain;
...
@@ -13,19 +13,14 @@ import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.io.buffer.DataBuffer
;
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.HttpStatus
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
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.ServerHttpResponse
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ServerWebExchange
;
import
org.springframework.web.server.ServerWebExchange
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Flux
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URI
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
...
@@ -40,7 +35,10 @@ import java.util.Objects;
...
@@ -40,7 +35,10 @@ import java.util.Objects;
@Component
@Component
public
class
AuthGlobalFilter
implements
GlobalFilter
,
Ordered
{
public
class
AuthGlobalFilter
implements
GlobalFilter
,
Ordered
{
// 用户注册、用户登录、发送手机号验证码
/**
* 放行URL
* 用户注册、用户登录、发送手机号验证码
*/
private
final
List
<
String
>
whiteUrls
=
Arrays
.
asList
(
"/login"
,
"/enroll"
,
"/sms/send/ver_code"
);
private
final
List
<
String
>
whiteUrls
=
Arrays
.
asList
(
"/login"
,
"/enroll"
,
"/sms/send/ver_code"
);
@Autowired
@Autowired
...
@@ -48,68 +46,29 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
...
@@ -48,68 +46,29 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
@Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
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
();
String
url
=
exchange
.
getRequest
().
getURI
().
getPath
();
// 1、判断url是否放行
// 1、判断url是否放行
boolean
isIgnore
=
whiteUrls
.
stream
().
anyMatch
(
url:
:
contains
);
boolean
isIgnore
=
whiteUrls
.
stream
().
anyMatch
(
url:
:
contains
);
if
(
isIgnore
)
{
if
(
isIgnore
)
{
log
.
info
(
"
请求放行,URL
:{}"
,
url
);
log
.
info
(
"
非校验URL放行
:{}"
,
url
);
return
chain
.
filter
(
exchange
);
return
chain
.
filter
(
exchange
);
}
}
String
token
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
// 2、未登录请求跳转登录
// 2、未登录请求跳转登录
String
token
=
exchange
.
getRequest
().
getHeaders
().
getFirst
(
"Authorization"
);
if
(
StringUtils
.
isBlank
(
token
))
{
if
(
StringUtils
.
isBlank
(
token
))
{
return
loginError
(
exchange
);
return
loginError
(
exchange
);
}
}
// 3、验证token
'
// 3、验证token
JSONObject
userJson
=
userDataService
.
getUserByToken
(
RedisKeys
.
UserKeys
.
TEMPORARY_TOKEN
.
getKey
()
+
token
);
JSONObject
userJson
=
userDataService
.
getUserByToken
(
RedisKeys
.
UserKeys
.
TEMPORARY_TOKEN
.
getKey
()
+
token
);
if
(
Objects
.
isNull
(
userJson
))
{
if
(
Objects
.
isNull
(
userJson
))
{
log
.
info
(
"token登录错误:{}"
,
token
);
log
.
info
(
"token登录错误:{}"
,
token
);
return
loginError
(
exchange
);
return
loginError
(
exchange
);
}
}
ServerHttpRequest
httpRequest
=
exchange
.
getRequest
().
mutate
().
header
(
"loginId"
,
userJson
.
getString
(
"id"
)).
header
(
"loginQcId"
,
userJson
.
getString
(
"qcId"
)).
build
();
if
(
"POST"
.
equals
(
method
))
{
return
chain
.
filter
(
exchange
.
mutate
().
request
(
httpRequest
).
build
());
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
);
}
}
@Override
@Override
...
@@ -123,12 +82,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
...
@@ -123,12 +82,7 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
response
.
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
response
.
getHeaders
().
add
(
"Content-Type"
,
"application/json;charset=UTF-8"
);
R
res
=
new
R
(
RCode
.
NOT_LOGIN_ERROR
);
R
res
=
new
R
(
RCode
.
NOT_LOGIN_ERROR
);
DataBuffer
buffer
=
response
.
bufferFactory
().
wrap
(
new
Gson
().
toJson
(
res
).
getBytes
(
StandardCharsets
.
UTF_8
));
DataBuffer
buffer
=
response
.
bufferFactory
().
wrap
(
new
Gson
().
toJson
(
res
).
getBytes
(
StandardCharsets
.
UTF_8
));
log
.
info
(
"------------- 结束 -------------"
);
return
response
.
writeWith
(
Flux
.
just
(
buffer
));
return
response
.
writeWith
(
Flux
.
just
(
buffer
));
}
}
private
void
logSave
()
{
}
}
}
src/main/java/com/promotion/gateway/filter/WrapperResponseGlobalFilter.java
浏览文件 @
26fbe23d
package
com
.
promotion
.
gateway
.
filter
;
//package com.promotion.gateway.filter;
//
//
import
com.alibaba.fastjson.JSONObject
;
//import com.alibaba.fastjson.JSONObject;
import
com.baomidou.mybatisplus.core.toolkit.StringUtils
;
//import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import
com.wangxiaolu.promotion.common.redis.RedisKeys
;
//import com.wangxiaolu.promotion.common.redis.RedisKeys;
import
io.netty.util.internal.StringUtil
;
//import io.netty.util.internal.StringUtil;
import
lombok.extern.slf4j.Slf4j
;
//import lombok.extern.slf4j.Slf4j;
import
org.reactivestreams.Publisher
;
//import org.reactivestreams.Publisher;
import
org.springframework.cloud.gateway.filter.GatewayFilterChain
;
//import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import
org.springframework.cloud.gateway.filter.GlobalFilter
;
//import org.springframework.cloud.gateway.filter.GlobalFilter;
import
org.springframework.core.Ordered
;
//import org.springframework.core.Ordered;
import
org.springframework.core.io.buffer.DataBuffer
;
//import org.springframework.core.io.buffer.DataBuffer;
import
org.springframework.core.io.buffer.DataBufferFactory
;
//import org.springframework.core.io.buffer.DataBufferFactory;
import
org.springframework.core.io.buffer.DataBufferUtils
;
//import org.springframework.core.io.buffer.DataBufferUtils;
import
org.springframework.core.io.buffer.DefaultDataBufferFactory
;
//import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import
org.springframework.http.HttpHeaders
;
//import org.springframework.http.HttpHeaders;
import
org.springframework.http.HttpStatus
;
//import org.springframework.http.HttpStatus;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
//import org.springframework.http.server.reactive.ServerHttpRequest;
import
org.springframework.http.server.reactive.ServerHttpRequestDecorator
;
//import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
//import org.springframework.http.server.reactive.ServerHttpResponse;
import
org.springframework.http.server.reactive.ServerHttpResponseDecorator
;
//import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import
org.springframework.stereotype.Component
;
//import org.springframework.stereotype.Component;
import
org.springframework.web.server.ServerWebExchange
;
//import org.springframework.web.server.ServerWebExchange;
import
reactor.core.publisher.Flux
;
//import reactor.core.publisher.Flux;
import
reactor.core.publisher.Mono
;
//import reactor.core.publisher.Mono;
//
import
java.io.UnsupportedEncodingException
;
//import java.io.UnsupportedEncodingException;
import
java.net.URI
;
//import java.net.URI;
import
java.nio.charset.Charset
;
//import java.nio.charset.Charset;
import
java.nio.charset.StandardCharsets
;
//import java.nio.charset.StandardCharsets;
import
java.util.Objects
;
//import java.util.Objects;
//
/**
///**
* @author : liqiulin
// * @author : liqiulin
* @date : 2024-05-24 15
// * @date : 2024-05-24 15
* @describe :
// * @describe :
*/
// */
//
@Component
//@Component
@Slf4j
//@Slf4j
public
class
WrapperResponseGlobalFilter
implements
GlobalFilter
,
Ordered
{
//public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
//
@Override
// @Override
public
int
getOrder
()
{
// public int getOrder() {
//-1 is response write filter, must be called before that
// //-1 is response write filter, must be called before that
return
-
2
;
// return -2;
}
// }
//
@Override
// @Override
public
Mono
<
Void
>
filter
(
ServerWebExchange
exchange
,
GatewayFilterChain
chain
)
{
// public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取response的 返回数据
// //获取response的 返回数据
ServerHttpResponse
originalResponse
=
exchange
.
getResponse
();
// ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory
bufferFactory
=
originalResponse
.
bufferFactory
();
// DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator
decoratedResponse
=
new
ServerHttpResponseDecorator
(
originalResponse
)
{
// ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
// @Override
public
Mono
<
Void
>
writeWith
(
Publisher
<?
extends
DataBuffer
>
body
)
{
// public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if
(
getStatusCode
().
equals
(
HttpStatus
.
OK
)
&&
body
instanceof
Flux
)
{
// if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
Flux
<?
extends
DataBuffer
>
fluxBody
=
Flux
.
from
(
body
);
// Flux<? extends DataBuffer> fluxBody = Flux.from(body);
//
// return super.writeWith(fluxBody.map(dataBuffer -> {
// return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
return
super
.
writeWith
(
fluxBody
.
buffer
().
map
(
dataBuffer
->
{
// //如果响应过大,会进行截断,出现乱码,然后看api DefaultDataBufferFactory有个join方法可以合并所有的流,乱码的问题解决
//如果响应过大,会进行截断,出现乱码,然后看api DefaultDataBufferFactory有个join方法可以合并所有的流,乱码的问题解决
// DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBufferFactory
dataBufferFactory
=
new
DefaultDataBufferFactory
();
// DataBuffer join = dataBufferFactory.join(dataBuffer);
DataBuffer
join
=
dataBufferFactory
.
join
(
dataBuffer
);
// byte[] content = new byte[join.readableByteCount()];
byte
[]
content
=
new
byte
[
join
.
readableByteCount
()];
// join.read(content);
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);
// //释放掉内存
// //释放掉内存
// DataBufferUtils.release(
dataBuffer
);
// DataBufferUtils.release(
join
);
//
//resultContent就是下游系统返回的内容,可以查看修改
//
//
String responseData = new String(content, Charset.forName("UTF-8"));
//
//打印响应日志
// log.info("------------- 返回信息 -------------");
// log.info("------------- 返回信息 -------------");
// log.info(
responseData
);
// log.info(
new String(content, StandardCharsets.UTF_8)
);
// log.info("------------- 返回信息 -------------");
// log.info("------------- 返回信息 -------------");
// byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
// return bufferFactory.wrap(content);
// return bufferFactory.wrap(uppedContent);
// }));
// } else {
}));
// log.error("响应code异常:{}", getStatusCode());
}
else
{
// }
log
.
error
(
"响应code异常:{}"
,
getStatusCode
());
// return super.writeWith(body);
}
// }
return
super
.
writeWith
(
body
);
// };
}
// return chain.filter(exchange.mutate().
};
//
return
chain
.
filter
(
exchange
.
mutate
().
// response(decoratedResponse).
//
response
(
decoratedResponse
).
// build());
// }
build
());
//}
}
\ No newline at end of file
}
\ No newline at end of file
src/main/java/com/promotion/gateway/filter/log/MyCachedBodyOutputMessage.java
0 → 100644
浏览文件 @
26fbe23d
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
浏览文件 @
26fbe23d
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
();
//请求路径
String
requestUrl
=
request
.
getPath
().
pathWithinApplication
().
value
();
Route
route
=
exchange
.
getAttribute
(
ServerWebExchangeUtils
.
GATEWAY_ROUTE_ATTR
);
// String ipAddress = IpUtil.getIpAddress(request);
SysLog
sysLog
=
SysLog
.
SysLogBuilder
.
sysLog
().
schema
(
request
.
getURI
().
getScheme
())
.
requestMethod
(
request
.
getMethodValue
())
.
requestPath
(
requestUrl
)
.
targetServer
(
route
.
getId
())
.
requestTime
(
new
Date
())
// .ip(ipAddress)
.
build
();
MediaType
mediaType
=
request
.
getHeaders
().
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
(
"请求参数:{}"
,
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
浏览文件 @
26fbe23d
package
com
.
promotion
.
gateway
.
filter
.
log
;
import
cn.hutool.core.date.DateUtil
;
import
java.io.Serializable
;
import
java.util.Date
;
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
;
public
String
getTargetServer
()
{
return
targetServer
;
}
public
void
setTargetServer
(
String
targetServer
)
{
this
.
targetServer
=
targetServer
;
}
public
String
getRequestPath
()
{
return
requestPath
;
}
public
void
setRequestPath
(
String
requestPath
)
{
this
.
requestPath
=
requestPath
;
}
public
String
getSchema
()
{
return
schema
;
}
public
void
setSchema
(
String
schema
)
{
this
.
schema
=
schema
;
}
public
String
getRequestBody
()
{
return
requestBody
;
}
public
void
setRequestBody
(
String
requestBody
)
{
this
.
requestBody
=
requestBody
;
}
public
String
getResponseData
()
{
return
responseData
;
}
public
void
setResponseData
(
String
responseData
)
{
this
.
responseData
=
responseData
;
}
public
String
getIp
()
{
return
ip
;
}
public
void
setIp
(
String
ip
)
{
this
.
ip
=
ip
;
}
public
Date
getRequestTime
()
{
return
requestTime
;
}
public
void
setRequestTime
(
Date
requestTime
)
{
this
.
requestTime
=
requestTime
;
}
public
Date
getResponseTime
()
{
return
responseTime
;
}
public
void
setResponseTime
(
Date
responseTime
)
{
this
.
responseTime
=
responseTime
;
}
public
Long
getExecuteTime
()
{
return
executeTime
;
}
public
void
setExecuteTime
(
Long
executeTime
)
{
this
.
executeTime
=
executeTime
;
}
public
String
getRequestMethod
()
{
return
requestMethod
;
}
public
void
setRequestMethod
(
String
requestMethod
)
{
this
.
requestMethod
=
requestMethod
;
}
@Override
public
String
toString
()
{
return
"\n SysLog{"
+
" targetServer='"
+
targetServer
+
'\''
+
",\n"
+
" requestPath='"
+
requestPath
+
'\''
+
",\n"
+
" requestMethod='"
+
requestMethod
+
'\''
+
",\n"
+
" schema='"
+
schema
+
'\''
+
",\n"
+
" requestBody='"
+
requestBody
+
'\''
+
",\n"
+
" responseData='"
+
responseData
+
'\''
+
",\n"
+
" ip='"
+
ip
+
'\''
+
",\n"
+
" requestTime="
+
DateUtil
.
formatDateTime
(
requestTime
)
+
",\n"
+
" responseTime="
+
DateUtil
.
formatDateTime
(
responseTime
)+
",\n"
+
" executeTime="
+
executeTime
+
'}'
;
}
public
static
final
class
SysLogBuilder
{
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
SysLogBuilder
()
{
}
public
static
SysLogBuilder
sysLog
()
{
return
new
SysLogBuilder
();
}
public
SysLogBuilder
targetServer
(
String
targetServer
)
{
this
.
targetServer
=
targetServer
;
return
this
;
}
public
SysLogBuilder
requestMethod
(
String
requestMethod
)
{
this
.
requestMethod
=
requestMethod
;
return
this
;
}
public
SysLogBuilder
requestPath
(
String
requestPath
)
{
this
.
requestPath
=
requestPath
;
return
this
;
}
public
SysLogBuilder
schema
(
String
schema
)
{
this
.
schema
=
schema
;
return
this
;
}
public
SysLogBuilder
requestBody
(
String
requestBody
)
{
this
.
requestBody
=
requestBody
;
return
this
;
}
public
SysLogBuilder
responseData
(
String
responseData
)
{
this
.
responseData
=
responseData
;
return
this
;
}
public
SysLogBuilder
ip
(
String
ip
)
{
this
.
ip
=
ip
;
return
this
;
}
public
SysLogBuilder
requestTime
(
Date
requestTime
)
{
this
.
requestTime
=
requestTime
;
return
this
;
}
public
SysLogBuilder
responseTime
(
Date
responseTime
)
{
this
.
responseTime
=
responseTime
;
return
this
;
}
public
SysLogBuilder
executeTime
(
Long
executeTime
)
{
this
.
executeTime
=
executeTime
;
return
this
;
}
public
SysLog
build
()
{
SysLog
sysLog
=
new
SysLog
();
sysLog
.
setTargetServer
(
targetServer
);
sysLog
.
setRequestMethod
(
requestMethod
);
sysLog
.
setRequestPath
(
requestPath
);
sysLog
.
setSchema
(
schema
);
sysLog
.
setRequestBody
(
requestBody
);
sysLog
.
setResponseData
(
responseData
);
sysLog
.
setIp
(
ip
);
sysLog
.
setRequestTime
(
requestTime
);
sysLog
.
setResponseTime
(
responseTime
);
sysLog
.
setExecuteTime
(
executeTime
);
return
sysLog
;
}
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论