网关常用工具类
# 过滤器
# 自定义过滤器
@Log4j2
public class UserTokenFilter extends AbstractGatewayFilterFactory {
/**
* 不需要登录的接口
*/
private static final String NO_LOGIN_PATH = "/api/v1/user/user/info/outer";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 获取请求路径
String path = request.getURI().getPath();
// 如果请求的是这些路径,直接放行
if (path.contains(NO_LOGIN_PATH)) {
return chain.filter(exchange);
}
HttpHeaders headers = request.getHeaders();
// 获取客户端唯一token
String token = headers.getFirst("Authorization");
if (StrUtil.isBlank(token)) {
return FilterErrorUtil.error(exchange, ResponseCode.TOKEN_EXPIRED);
}
try {
String bearer = "Bearer ";
if (!token.contains(bearer)) {
return FilterErrorUtil.error(exchange, ResponseCode.TOKEN_EXPIRED);
}
token = token.replace(bearer, "");
// 判断token是否失效
if (!TokenUtil.checkToken(token)) {
return FilterErrorUtil.error(exchange, ResponseCode.TOKEN_EXPIRED);
}
// 解密token,获取信息,存入请求头
Map map = JSONObject.parseObject(TokenUtil.getUserInfo(token), Map.class);
request.mutate().header(HttpRequestHeaderName.USER_ID, map.get("id").toString());
request.mutate().header(HttpRequestHeaderName.OPEN_ID, map.get("openid").toString());
} catch (Exception e) {
e.printStackTrace();
return FilterErrorUtil.error(exchange, ResponseCode.TOKEN_EXPIRED);
}
return chain.filter(exchange);
};
}
# FilterErrorUtil
public static Mono<Void> error(ServerWebExchange exchange, ResponseCode info) {
ServerHttpRequest request = exchange.getRequest();
log.warn("错误请求,请求路径 {}", request.getURI().getPath());
StrBuilder msg = new StrBuilder();
msg.append("{\"code\":").append(info.getCode()).append(",\"message\":\"").append(info.getMessage()).append("\"}");
byte[] bytes = msg.toString().getBytes(StandardCharsets.UTF_8);
ServerHttpResponse response = exchange.getResponse();
DataBuffer data = response.bufferFactory().wrap(bytes);
response.getHeaders().add("Content-Type", "application/json;charset=utf-8");
return response.writeWith(Flux.just(data));
}
# 配置类
@Bean
public UserTokenFilter userTokenFilter() {
return new UserTokenFilter();
}
# 微服务拦截
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: user-6004 #socket微服务
uri: lb://user-6004
predicates:
- Path=/api/v1/user/**
filters:
# 自定义过滤器
- UserTokenFilter
# 统一异常处理
# CustomErrorWebFluxAutoConfiguration
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class CustomErrorWebFluxAutoConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public CustomErrorWebFluxAutoConfiguration(ServerProperties serverProperties,
ResourceProperties resourceProperties,
ObjectProvider<ViewResolver> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.orderedStream()
.collect(Collectors.toList());
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
JsonErrorWebExceptionHandler exceptionHandler = new JsonErrorWebExceptionHandler(
errorAttributes,
resourceProperties,
this.serverProperties.getError(),
applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
}
# JsonErrorWebExceptionHandler
public class JsonErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
public JsonErrorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties,
ErrorProperties errorProperties,
ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
Throwable error = super.getError(request);
Map<String, Object> errorAttributes = new HashMap<>(8);
errorAttributes.put("message", error.getMessage());
errorAttributes.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
errorAttributes.put("method", request.methodName());
errorAttributes.put("path", request.path());
return errorAttributes;
}
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
@Override
protected int getHttpStatus(Map<String, Object> errorAttributes) {
// 这里其实可以根据errorAttributes里面的属性定制HTTP响应码
return HttpStatus.OK.value();
}
}