springboot项目引入Sentinel熔断
本文是springboot项目+nacos进行引入,sentiel需自行按照部署
1.springboot包要是2.2.5或以上
<dubbo.version>2.7.7</dubbo.version>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<chainwork-boot.version>1.0.5-SNAPSHOT</chainwork-boot.version>
<nacos.version>0.2.7</nacos.version>
<spring-cloud-nacos-config.version>2.2.5.RELEASE</spring-cloud-nacos-config.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<spring-cloud-nacos-discovery.version>2.2.5.RELEASE</spring-cloud-nacos-discovery.version>
<!--
<arthas.version>3.4.3</arthas.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<nacos-client.version>1.4.1</nacos-client.version>
<redisson.version>3.13.6</redisson.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
2.项目后端需依赖包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<!-- Sentinel数据源之 Nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version>
</dependency>
3.项目前端需依赖包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version>
</dependency>
4.后端 bootstrap.yml需配置
#server:
# port: 8888
spring:
# application:
# name: test-server
main:
allow-bean-definition-overriding: true
cloud:
sentinel:
datasource:
# 流控规则,名字任意
ds-flow:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-flow-rules
## 配置存储的格式
data-type: json
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
rule-type: flow
## 配置降级规则,名字任意
ds-degrade:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-degrade-rules
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
## 配置存储的格式
data-type: json
## rule-type设置对应得规则类型,总共七大类型,在com.alibaba.cloud.sentinel.datasource.RuleType这个枚举类中有体现
rule-type: degrade
## 配置系统规则,名字任意
ds-system:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-system-rules
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
## 配置存储的格式
data-type: json
rule-type: system
nacos:
discovery:
server-addr: 11.11.11.11:8848
# group: lj
config:
# 配置中心地址配置
server-addr: 11.11.11.11:8848
# 定义配置文件后缀为.properties, dataId=${spring.application.name}-${spring.profiles.active}.properties
file-extension: properties
group: prd
# 定义配置中心分组:
shared-configs[0]: #多个从0开始递增 扩展的是数字越大的优先级越高
data-id: global-server-prd.properties #配置文件名
group: DEFAULT_GROUP #分组名称
# refresh: true #配置扩展属性动态刷新
shared-configs[1]:
data-id: test-service-prd.properties
# data-id: test-service-test-sit.properties
group: prd
# refresh: true
profiles:
# 定义环境为dev
active: prd
5.前端 bootstrap.yml需配置
server:
# port: 8888
servlet:
context-path: /test-web
spring:
# application:
# name: test-web
main:
allow-bean-definition-overriding: true
cloud:
sentinel:
# eager: true
# filter:
# enabled: false
# transport:
# dashboard: 127.0.0.1:12180
# web-context-unify: false
datasource:
# 流控规则,名字任意
ds-flow:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-flow-rules
## 配置存储的格式
data-type: json
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
rule-type: flow
## 配置降级规则,名字任意
ds-degrade:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-degrade-rules
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
## 配置存储的格式
data-type: json
## rule-type设置对应得规则类型,总共七大类型,在com.alibaba.cloud.sentinel.datasource.RuleType这个枚举类中有体现
rule-type: degrade
## 配置系统规则,名字任意
ds-system:
nacos:
## nacos的地址
server-addr: 11.11.11.11:8848
## 配置ID
dataId: ${spring.application.name}-system-rules
## 配置分组,默认是DEFAULT_GROUP
groupId: SENTINEL_GROUP
## 配置存储的格式
data-type: json
rule-type: system
nacos:
discovery:
server-addr: 11.11.11.11:8848
config:
# 配置中心地址配置
server-addr: 11.11.11.11:8848
# 定义配置文件后缀为.properties, dataId=${spring.application.name}-${spring.profiles.active}.properties
file-extension: properties
# group: sit
# 定义配置中心分组:
shared-configs[0]: #多个从0开始递增 扩展的是数字越大的优先级越高
data-id: global-web-prd.properties #配置文件名
group: DEFAULT_GROUP #分组名称
refresh: true #配置扩展属性动态刷新
shared-configs[1]:
data-id: test-web-prd.properties
group: prd
# refresh: true
6.后端引入异常处理及配置类
import cn.hutool.json.JSONUtil;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.sinoservices.beans.ResultMessage;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sentinel异常处理程序
*/
@Configuration
public class SentinelCustomBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
ResultMessage resultMessage = new ResultMessage();
if (e instanceof FlowException) {
// 限流
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求繁忙,请稍后请求哦");
} else if (e instanceof DegradeException) {
// 熔断
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求在排队,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求在排队,请稍后请求哦");
} else if (e instanceof ParamFlowException) {
// 参数热点
resultMessage.setSuccess(false);
resultMessage.setMessage("ParamFlow系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("ParamFlow系统请求繁忙,请稍后请求哦");
} else if (e instanceof SystemBlockException) {
//系统保护
resultMessage.setSuccess(false);
resultMessage.setMessage("系统资源繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统资源繁忙,请稍后请求哦");
} else if (e instanceof AuthorityException) {
}
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(resultMessage));
}
}
**
* 常量
*
* @description: 全局异常处理
*/
@Slf4j
@ControllerAdvice
public class TestServerGlobalExceptionHandler {
/**
* validator 方法参数校验
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Message handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("参数校验异常:{},{}", e.getMessage(), e);
FieldError fieldError = e.getBindingResult().getFieldError();
Message message = MessageFactory.getMessage();
message.setSuccess(false);
message.addMessage(fieldError.getDefaultMessage());
//message.addMessage(fieldError.getField() + fieldError.getDefaultMessage());
return message;
}
@ExceptionHandler(IllegalArgumentException.class)
@ResponseBody
public Message handleFeignException(IllegalArgumentException e) {
log.error("IllegalArgumentException异常:{},{}", e.getMessage(), e);
Message message = MessageFactory.getMessage();
message.setSuccess(false);
message.addMessage(e.getMessage());
return message;
}
@ExceptionHandler(FeignException.class)
@ResponseBody
public ResultMessage handleFeignException(FeignException e) {
log.error("openFeign异常:{},{}", e.getMessage(), e);
ResultMessage resultMessage = new ResultMessage();
resultMessage.setSuccess(false);
resultMessage.setMessage(e.getMessage());
resultMessage.setErrorDetailMessage(e.getMessage());
return resultMessage;
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Message handleException(Exception e) {
log.error("接口异常:{},{}", e.getMessage(), e);
Message message = MessageFactory.getMessage();
message.setSuccess(false);
message.addMessage(e.getMessage());
return message;
}
@ExceptionHandler(StaleObjectStateException.class)
@ResponseBody
public Message versionErrorException(Exception e) {
log.error("数据库修改版本冲突异常:{},{}", e.getMessage(), e);
Message message = MessageFactory.getMessage();
message.setSuccess(false);
message.addMessage("数据版本冲突,请刷新后再操作");
return message;
}
@ExceptionHandler(BlockException.class)
@ResponseBody
public ResultMessage sentinelBlockHandler(BlockException e) {
log.error("sentinelBlock异常:{},{}", e.getMessage(), e);
ResultMessage resultMessage = new ResultMessage();
resultMessage.setSuccess(false);
resultMessage.setMessage(e.getRule() + "系统繁忙,请稍后处理");
resultMessage.setErrorDetailMessage(e.getRule() + "系统繁忙,请稍后处理");
return resultMessage;
}
}
import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.cloud.sentinel.SentinelProperties.Filter;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.DefaultBlockExceptionHandler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Optional;
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({SentinelWebInterceptor.class})
@EnableConfigurationProperties({SentinelProperties.class})
public class SentinelWebAutoConfiguration implements WebMvcConfigurer {
private static final Logger log = LoggerFactory.getLogger(SentinelWebAutoConfiguration.class);
@Autowired
private SentinelProperties properties;
@Autowired
private Optional<UrlCleaner> urlCleanerOptional;
@Autowired
private Optional<BlockExceptionHandler> blockExceptionHandlerOptional;
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
public SentinelWebAutoConfiguration() {
}
public void addInterceptors(InterceptorRegistry registry) {
if (this.sentinelWebInterceptorOptional.isPresent()) {
Filter filterConfig = this.properties.getFilter();
registry.addInterceptor((HandlerInterceptor) this.sentinelWebInterceptorOptional.get()).order(filterConfig.getOrder()).addPathPatterns(filterConfig.getUrlPatterns());
log.info("[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.", filterConfig.getUrlPatterns());
}
}
@Bean
public SentinelWebInterceptor sentinelWebInterceptor(SentinelWebMvcConfig sentinelWebMvcConfig) {
return new SentinelWebInterceptor(sentinelWebMvcConfig);
}
@Bean
public SentinelWebMvcConfig sentinelWebMvcConfig() {
SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
sentinelWebMvcConfig.setHttpMethodSpecify(this.properties.getHttpMethodSpecify());
sentinelWebMvcConfig.setWebContextUnify(this.properties.getWebContextUnify());
if (this.blockExceptionHandlerOptional.isPresent()) {
this.blockExceptionHandlerOptional.ifPresent(sentinelWebMvcConfig::setBlockExceptionHandler);
} else if (StringUtils.hasText(this.properties.getBlockPage())) {
sentinelWebMvcConfig.setBlockExceptionHandler((request, response, e) -> {
response.sendRedirect(this.properties.getBlockPage());
});
} else {
sentinelWebMvcConfig.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
}
this.urlCleanerOptional.ifPresent(sentinelWebMvcConfig::setUrlCleaner);
this.requestOriginParserOptional.ifPresent(sentinelWebMvcConfig::setOriginParser);
return sentinelWebMvcConfig;
}
}
7.前端引入异常处理及配置类
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* @description:
* @author: John.Zhang
* @date: 2023年03月02日
* @version: 1.0.0
*/
@Component
@RefreshScope
@Data
public class FilterAssignUrlConfig {
/**
* 忽略静态资源
*/
@Value("${request.ignore.requestSuffix}")
public String ignoreRequestSuffix;
/**
* 忽略登录请求
*/
@Value("${request.ignore.requestUrl}")
public String ignoreRequestUrl;
}
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description:
*/
@Configuration
public class FilterContextConfig {
@Autowired
private SentinelCustomFilter sentinelCustomFilter;
@Autowired
private FilterAssignUrlConfig filterAssignUrlConfig;
/**
* https://github.com/alibaba/Sentinel/issues/1213
*
* @return
*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(sentinelCustomFilter);
registration.addUrlPatterns("/*");
registration.addInitParameter("excludedUris", filterAssignUrlConfig.getIgnoreRequestUrl());
registration.addInitParameter("excludedRequestFileExtension", filterAssignUrlConfig.getIgnoreRequestSuffix());
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
registration.setName("sentinelCustomFilter");
registration.setOrder(1);
return registration;
}
}
import com.alibaba.csp.sentinel.*;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class SentinelCustomFilter implements Filter {
/**
* Specify whether the URL resource name should contain the HTTP method prefix (e.g. {@code POST:}).
*/
public static final String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY";
/**
* If enabled, use the default context name, or else use the URL path as the context name,
* {@link WebServletConfig#WEB_SERVLET_CONTEXT_NAME}. Please pay attention to the number of context (EntranceNode),
* which may affect the memory footprint.
*
* @since 1.7.0
*/
public static final String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY";
private final static String COLON = ":";
private boolean httpMethodSpecify = false;
private boolean webContextUnify = true;
private String[] excludedUris;
private String excludedRequestFileExtension;
@Override
public void init(FilterConfig filterConfig) {
String param = filterConfig.getInitParameter("excludedUris");
if (StringUtils.isNotBlank(param)) {
this.excludedUris = param.split(",");
}
String excludedRequestFileExtension = filterConfig.getInitParameter("excludedRequestFileExtension");
if (StringUtils.isNotBlank(excludedRequestFileExtension)) {
this.excludedRequestFileExtension = excludedRequestFileExtension;
}
httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY));
if (filterConfig.getInitParameter(WEB_CONTEXT_UNIFY) != null) {
webContextUnify = Boolean.parseBoolean(filterConfig.getInitParameter(WEB_CONTEXT_UNIFY));
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest sRequest = (HttpServletRequest) request;
Entry urlEntry = null;
String target = null;
boolean reqFlag = false;
try {
target = FilterUtil.filterTarget(sRequest);
// 定义表示变量 并验证用户请求URI 是否包含不过滤路径
for (String uri : excludedUris) {
if (target.equals(uri)) {
reqFlag = true;
}
if (target.indexOf(".") > -1) {
if (excludedRequestFileExtension.contains(target.substring(target.lastIndexOf(".") + 1, target.length()))) {
reqFlag = true;
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
try {
if (!reqFlag) {
// Clean and unify the URL.
// For REST APIs, you have to clean the URL (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or
// the amount of context and resources will exceed the threshold.
UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner();
if (urlCleaner != null) {
target = urlCleaner.clean(target);
}
// If you intend to exclude some URLs, you can convert the URLs to the empty string ""
// in the UrlCleaner implementation.
if (!StringUtil.isEmpty(target)) {
// Parse the request origin using registered origin parser.
String origin = parseOrigin(sRequest);
String contextName = webContextUnify ? WebServletConfig.WEB_SERVLET_CONTEXT_NAME : target;
ContextUtil.enter(contextName, origin);
if (httpMethodSpecify) {
// Add HTTP method prefix if necessary.
String pathWithHttpMethod = sRequest.getMethod().toUpperCase() + COLON + target;
urlEntry = SphU.entry(pathWithHttpMethod, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
} else {
urlEntry = SphU.entry(target, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
}
}
}
chain.doFilter(request, response);
} catch (BlockException e) {
HttpServletResponse sResponse = (HttpServletResponse) response;
HttpServletRequest sRequest2 = (HttpServletRequest) request;
// Return the block page, or redirect to another URL.
// WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e);
StringBuffer url = sRequest2.getRequestURL();
if ("GET".equals(sRequest2.getMethod()) && StringUtil.isNotBlank(sRequest2.getQueryString())) {
url.append("?").append(sRequest2.getQueryString());
}
ResultMessage resultMessage = new ResultMessage();
if (e instanceof FlowException) {
// 限流
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求繁忙,请稍后请求哦");
} else if (e instanceof DegradeException) {
// 熔断
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求在排队,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求在排队,请稍后请求哦");
} else if (e instanceof ParamFlowException) {
// 参数热点
resultMessage.setSuccess(false);
resultMessage.setMessage("ParamFlow系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("ParamFlow系统请求繁忙,请稍后请求哦");
} else if (e instanceof SystemBlockException) {
//系统保护
resultMessage.setSuccess(false);
resultMessage.setMessage("系统资源繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统资源繁忙,请稍后请求哦");
}
if (StringUtil.isBlank(WebServletConfig.getBlockPage())) {
sResponse.setStatus(WebServletConfig.getBlockPageHttpStatus());
sResponse.setCharacterEncoding("utf-8");
sResponse.setHeader("Content-Type", "application/json;charset=utf-8");
PrintWriter out = sResponse.getWriter();
String blockMsg = JSON.toJSONString(resultMessage);
out.print(blockMsg);
out.flush();
out.close();
} else {
String redirectUrl = WebServletConfig.getBlockPage() + "?http_referer=" + url.toString();
sResponse.sendRedirect(redirectUrl);
}
} catch (IOException | ServletException | RuntimeException e2) {
Tracer.traceEntry(e2, urlEntry);
throw e2;
} finally {
if (urlEntry != null) {
urlEntry.exit();
}
ContextUtil.exit();
}
}
private String parseOrigin(HttpServletRequest request) {
RequestOriginParser originParser = WebCallbackManager.getRequestOriginParser();
String origin = EMPTY_ORIGIN;
if (originParser != null) {
origin = originParser.parseOrigin(request);
if (StringUtil.isEmpty(origin)) {
return EMPTY_ORIGIN;
}
}
return origin;
}
@Override
public void destroy() {
}
private static final String EMPTY_ORIGIN = "";
}
import cn.hutool.json.JSONUtil;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sentinel异常处理程序
*/
@Configuration
public class SentinelCustomBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
ResultMessage resultMessage = new ResultMessage();
if (e instanceof FlowException) {
// 限流
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求繁忙,请稍后请求哦");
} else if (e instanceof DegradeException) {
// 熔断
resultMessage.setSuccess(false);
resultMessage.setMessage("系统请求在排队,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统请求在排队,请稍后请求哦");
} else if (e instanceof ParamFlowException) {
// 参数热点
resultMessage.setSuccess(false);
resultMessage.setMessage("ParamFlow系统请求繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("ParamFlow系统请求繁忙,请稍后请求哦");
} else if (e instanceof SystemBlockException) {
//系统保护
resultMessage.setSuccess(false);
resultMessage.setMessage("系统资源繁忙,请稍后请求哦");
resultMessage.setErrorDetailMessage("系统资源繁忙,请稍后请求哦");
} else if (e instanceof AuthorityException) {
}
response.setCharacterEncoding("utf-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(JSONUtil.toJsonStr(resultMessage));
}
}
8.nacos需增加对应配置
spring.cloud.sentinel.transport.dashboard=11.111.1.112:11180
spring.cloud.sentinel.web-context-unify=false
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.filter.enabled=false
feign.sentinel.enabled=true
9.启动项目后就可在sentiel中进行规则配置