Gateway 过滤器,过滤器统一异常处理
Posted 正怒月神
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gateway 过滤器,过滤器统一异常处理相关的知识,希望对你有一定的参考价值。
以下内容,都很重要
以下内容,都很重要
以下内容,都很重要
请勿忽略
一, 配置文件
spring:
cloud:
gateway:
globalcors:
cors-configurations: #cors
'[/**]':
allowed-headers: "*"
allowed-origins: "*"
allowed-methods: "*"
# discovery:
# locator:
# lower-case-service-id: true
# enabled: true
routes:
- id: web-mac
uri: lb://web-mac
predicates:
- Path=/web-mac/**
filters:
- StripPrefix=1
- Token_Mac=true
解释:
一, cors 不多说了,跨域设置
二, discovery
这个当中的 locator.enabled 必须注释掉。
它会影响到过滤的转发功能。
三,属性
id:随便起名字
uri:lb开头,无需更改。web-mac是注册中心的application name(eruake显示大写,配置里用小写没关系)
predicates:匹配规则
filters:过滤器
在使用过滤器时,StripPrefix=1 必须!
Token_Mac 是我的过滤器,True是代表Config中是否开启。
二,过滤器
package com.tenyears.gateway.filter;
/**
* @description :
* @auther Tyler
* @date 2021/8/12
*/
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class Token_MacGatewayFilterFactory extends AbstractGatewayFilterFactory<Token_MacGatewayFilterFactory.Config> {
private static final String TOKEN_HEADER="Authorization";
private static final String TOKEN_IS_INVALID = "Token is invalid";
public Token_MacGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("enabled");
}
@Override
public GatewayFilter apply(Token_MacGatewayFilterFactory.Config config) {
System.out.println("TokenGatewayFilterFactory begin");
return (exchange, chain) -> {
if (!config.isEnabled()) {
return chain.filter(exchange);
}
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
String token = headers.getFirst(TOKEN_HEADER);
System.out.println("token : "+token);
if (StringUtils.isEmpty(token) ) {
throw new RuntimeException(TOKEN_IS_INVALID);
// response.setStatusCode(HttpStatus.UNAUTHORIZED);
// return response.setComplete();
}
//验证token,这里举个例子
if (!token.equals("123") ) {
throw new RuntimeException(TOKEN_IS_INVALID);
// response.setStatusCode(HttpStatus.UNAUTHORIZED);
// return response.setComplete();
}
System.out.println("TokenGatewayFilterFactory end");
return chain.filter(exchange);
};
}
public static class Config {
// 控制是否开启认证
private boolean enabled;
public Config() {}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}
一,继承自AbstractGatewayFilterFactory
二,过滤器名:Token_MacGatewayFilterFactory
必须 GatewayFilterFactory 结尾!
三,统一异常处理
package com.tenyears.gateway.advice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tenyears.model.common.ApiResult;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* @description :
* @auther Tyler
* @date 2021/8/12
*/
@Order(-1)
@Configuration
public class GlobalErrorExceptionHandler implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper=new ObjectMapper();
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
// 设置返回JSON
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus());
}
return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
//返回响应结果
ApiResult<String> result=new ApiResult<>();
result.setCodeToFail(ex.getMessage());
return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
}
catch (JsonProcessingException e) {
return bufferFactory.wrap(new byte[0]);
}
}));
}
}
filter 抛出的异常,会被GlobalErrorExceptionHandler 统一处理
ApiResult<T>
是我自定义的返回结果。
package com.tenyears.model.common;
/**
* Created by Tyler on 2017/6/20.
*/
@Data
public class ApiResult<T> {
public static final String FAIL_CODE = "0"; //失败码
public static final String SUC_CODE = "1"; //成功码
public static final String ERROR_CODE = "2"; //错误码
public static final String SUC_MESSAGE = "Operate successfully"; //成功信息
public static final String FAIL_MESSAGE = "Operation failure"; //失败信息
public static final String ERROR_MESSAGE = "System Error"; //错误信息
public static final String NOACCESS_MESSAGE = "No permission to access this page."; //无权操作
/**
* 代码
* 0 失败
* 1 成功
* 2 错误
* @mock 1
*/
private String code = FAIL_CODE;
/**
* 信息(对应code)
* Operate successfully
* Operation failure
* System Error
* @mock Operate successfully
*/
private String message = FAIL_MESSAGE;
/**
* 模型
*/
private T data;
/**
* 当前页(分页时有效)
*/
private Integer page_index = -1;
/**
* 条目(分页时有效)
*/
private Integer page_size= -1;
/**
* 总页数(分页时有效)
*/
private Integer total_pages=-1;
/**
* 总条目数(分页时有效)
*/
private Integer total_elements=-1;
public void setCode(String code, String message) {
this.code = code;
this.message = message;
}
public void setCodeToSuccessed() {
this.code = SUC_CODE;
this.message = SUC_MESSAGE;
}
public void setCodeToSuccessed(T data) {
this.data = data;
this.code = SUC_CODE;
this.message = SUC_MESSAGE;
}
public void setCodeToError(String message) {
this.code = ERROR_CODE;
this.message = message;
}
public void setCodeToError() {
this.code = ERROR_CODE;
this.message = ERROR_MESSAGE;
}
public void setCodeToFail(String message) {
this.code = ERROR_CODE;
this.message = message;
}
public void setCodeToFail() {
this.code = FAIL_CODE;
this.message = FAIL_MESSAGE;
}
public void setCodeByNoAccess() {
this.code = FAIL_CODE;
this.message = NOACCESS_MESSAGE;
}
public boolean isSuccess() {
return SUC_CODE.equals(code);
}
}
以上是关于Gateway 过滤器,过滤器统一异常处理的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud 统一网关Gateway -- 全局过滤器 GlobalFilter@Order注解过滤器链执行顺序Gateway跨域问题处理
SpringCloud H版 GateWay 过滤器讲解 及 使用Guava 统一限流处理。