[BUG] 系统规则与授权规则不生效
- Dominant language
- Java
- Stars
- 23.1k
- Forks
- 8.1k
- PR merge metrics
- No merged PRs in 30d
Description
## Issue Description
Type: *bug report*
### Describe what happened
基于毕业版本的SpringCloudAlibaba+SpringCloud+SpringBoot下配置并使用Sentinel的系统规则与授权规则不生效。
三个基础版本如图所示:

Sentinel相关依赖如图所示:

定义测试用的Controller类:
`package com.nriet.cipas.controller.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.nriet.cipas.common.util.exception.ExceptionUtils;
import com.nriet.cipas.environment.annotation.NotControllerResponseAdvice;
import com.nriet.cipas.service.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@Slf4j
public class UserController {
@Autowired
private IUserService userService;
@GetMapping("/user/getUserByName")
@SentinelResource(value = "/user/getUserByName",blockHandler = "blockHandlerGetUserByName")
public String getUserByName(@RequestParam("userName") String userName){
return userService.selectUserByName(userName);
}
public String blockHandlerGetUserByName(String userName, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}
@GetMapping("/user/{userId}")
@SentinelResource(value = "/user/userId",blockHandler = "blockHandler")
public String userId(@PathVariable("userId") String userId){
return "checked!";
}
public String blockHandler(String userId, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}
@GetMapping("/user/authority")
@SentinelResource(value = "/user/authority",blockHandler = "blockHandlerAuthority")
public String authority(@RequestParam("userId") String userId){
return "passed!";
}
public String blockHandlerAuthority(String userId, BlockException ex)
{
ExceptionUtils.extracted(ex);
return "";
}
}
`
其他方法1:
`package com.nriet.cipas.common.util.exception;
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;
public class ExceptionUtils {
public static void extracted(BlockException ex) {
if(ex instanceof FlowException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_FLOW_ERROR.getCode(), "selectUserByName" + "方法被限流了,请稍后重试");
} else if (ex instanceof DegradeException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_DEGRADE_ERROR.getCode(), "selectUserByName" + "方法被降级熔断了,请稍后重试");
} else if (ex instanceof ParamFlowException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_PARAMS_ERROR.getCode(), "selectUserByName" + "方法触发热点参数限流,请稍后重试");
} else if (ex instanceof AuthorityException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_AUTH_ERROR.getCode(), "selectUserByName" + "方法访问权限不足,请联系服务管理员");
} else if (ex instanceof SystemBlockException) {
throw new ApplicationDefinedException(ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getCode(), "selectUserByName" + "方法触发系统保护了,请稍后重试");
}
}
}
`
全局异常处理类:
`package com.nriet.cipas.environment.exception;
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.nriet.cipas.common.util.exception.ApplicationDefinedException;
import com.nriet.cipas.common.util.exception.ExceptionEnum;
import com.nriet.cipas.instance.vo.result.ResultVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.List;
import java.util.stream.Collectors;
@ControllerAdvice
@ResponseBody //统一在类前面加上@ResponseBody注解,这样在方法上就不需要添加了,返回的数据都是json格式的
public class GlobalExceptionAdvice {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionAdvice.class);
/**
* 使用form data方式调用接口,校验异常抛出 BindException
* @param e
* @return
*/
@ExceptionHandler({BindException.class})
public ResultVO BindExceptionHandler(BindException e) {
List fieldErrors = e.getBindingResult().getFieldErrors();
List collect = fieldErrors.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.ARGUMENT_ERROR.getCode(),ExceptionEnum.ARGUMENT_ERROR.getMsg() , collect.toString());
}
/**
* 处理参数校验异常。使用 json 请求体调用接口,校验异常抛出 MethodArgumentNotValidException
* 调用/globalExceptionTest/addUser接口测试。
* 传入:
* {"account":"222sada99999999999","password":"3","email":"a519991925"}
* 报错为:
* {
* "code": 108,
* "message": "参数不合法",
* "data": "[用户id不能为空, 邮箱格式不正确, 密码长度必须是6-16个字符, 账号长度必须是6-11个字符]"
* }
* @param e
* @return
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResultVO MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
List fieldErrors = e.getBindingResult().getFieldErrors();
List collect = fieldErrors.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
logger.error(getMsg(e));
logger.error(collect.toString());
return new ResultVO<>(ExceptionEnum.ARGUMENT_ERROR.getCode(),ExceptionEnum.ARGUMENT_ERROR.getMsg() , collect);
}
/**
* 处理业务自定义异常
* @param e
* @return
*/
@ExceptionHandler(value = ApplicationDefinedException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO ApplicationDefinedExceptionHandler(ApplicationDefinedException e){
logger.error(getMsg(e));
return new ResultVO<>(e.getCode(),e.getMessage(),null);
}
@ExceptionHandler(value = FlowException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO flowExceptionHandler(FlowException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_FLOW_ERROR.getCode(),ExceptionEnum.SENTINEL_FLOW_ERROR.getMsg(),null);
}
@ExceptionHandler(value = DegradeException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO degradeExceptionHandler(DegradeException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_DEGRADE_ERROR.getCode(),ExceptionEnum.SENTINEL_DEGRADE_ERROR.getMsg(),null);
}
@ExceptionHandler(value = ParamFlowException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO paramFlowException(ParamFlowException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_PARAMS_ERROR.getCode(),ExceptionEnum.SENTINEL_PARAMS_ERROR.getMsg(),null);
}
@ExceptionHandler(value = AuthorityException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO authorityExceptionHandler(AuthorityException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_AUTH_ERROR.getCode(),ExceptionEnum.SENTINEL_AUTH_ERROR.getMsg(),null);
}
@ExceptionHandler(value = SystemBlockException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO systemBlockExceptionHandler(SystemBlockException e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getCode(),ExceptionEnum.SENTINEL_SYSTEM_BLOCK_ERROR.getMsg(),null);
}
/**
* 处理其它异常
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
//ResponseStatus没有必要了,因为我们在全局异常处理类中已经设置了,这里统一用200即可
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ResultVO exceptionHandler(Exception e){
logger.error(getMsg(e));
return new ResultVO<>(ExceptionEnum.UNKNOW_ERROR.getCode(),ExceptionEnum.UNKNOW_ERROR.getMsg(),null);
}
private static String getMsg(Exception e) {
StackTraceElement[] stackTrace = e.getStackTrace();
StringBuffer sb = new StringBuffer();
sb.append(e.toString()).append("\r\n");
for (StackTraceElement stackTraceElement : stackTrace) {
sb.append("\tat ").append(stackTraceElement.getClassName()).append(".")
.append(stackTraceElement.getMethodName())
.append("(").append(stackTraceElement.getFileName()).append(":").append(stackTraceElement.getLineNumber())
.append(")\r\n");
}
return sb.toString();
}
}
`
origin解析类:
`package com.nriet.cipas.environment.configuration;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
// 当前 流控应用 放在了请求参数里面,可以放到的地方有很多,比如 参数/请求头/session/等等
return httpServletRequest.getParameter("sourceName");
}
}
`
bootstrap.properties相关Sentinel配置:
`#sentinel
spring.cloud.sentinel.transport.dashboard=localhost:8885
spring.cloud.sentinel.transport.clientIp=${spring.cloud.client.ip-address}
spring.cloud.sentinel.transport.port=18719
spring.cloud.sentinel.web-context-unify=false
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.flow.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.flow.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.flow.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.flow.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.flow.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.flow.nacos.data-type=json
spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow
spring.cloud.sentinel.datasource.degrade.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.degrade.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.degrade.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.degrade.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.degrade.nacos.data-id=${spring.application.name}-degrade-rules
spring.cloud.sentinel.datasource.degrade.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.degrade.nacos.data-type=json
spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade
#
spring.cloud.sentinel.datasource.system.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.system.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.system.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.system.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.system.nacos.data-id=${spring.application.name}-system-rules
spring.cloud.sentinel.datasource.system.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.system.nacos.data-type=json
spring.cloud.sentinel.datasource.system.nacos.rule-type=system
#
spring.cloud.sentinel.datasource.authority.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.authority.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.authority.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.authority.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.authority.nacos.data-id=${spring.application.name}-authority-rules
spring.cloud.sentinel.datasource.authority.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.authority.nacos.data-type=json
spring.cloud.sentinel.datasource.authority.nacos.rule-type=authority
#
spring.cloud.sentinel.datasource.param-flow.nacos.server-addr=${spring.cloud.nacos.config.server-addr}
spring.cloud.sentinel.datasource.param-flow.nacos.namespace=${spring.cloud.nacos.config.namespace}
spring.cloud.sentinel.datasource.param-flow.nacos.username=${spring.cloud.nacos.config.username}
spring.cloud.sentinel.datasource.param-flow.nacos.password=${spring.cloud.nacos.config.password}
spring.cloud.sentinel.datasource.param-flow.nacos.data-id=${spring.application.name}-param-flow-rules
spring.cloud.sentinel.datasource.param-flow.nacos.groupId=SENTINEL_GROUP
spring.cloud.sentinel.datasource.param-flow.nacos.data-type=json
spring.cloud.sentinel.datasource.param-flow.nacos.rule-type=param-flow`
Sentinel-dashboard版本为1.8.0,可以读取、新增、修改、删除该应用程序所有配置。

应用服务启动正常,相关测试接口测试正常(包括限流、降级、热点三个规则,都能正常使用)

### Describe what you expected to happen
无论通过手动修改Nacos上的关于系统规则与授权规则的配置文件、还是通过Dashboard修改,都无法生效。


例如以20并发调用测试接口,检验系统规则在并发数为3的生效情况,shiji实际并未触发:



例如配置授权规则,以白名单方式强制限定仅有“cipas-example2”的应用才能调用测试接口,也无法生效。


请问该如何处理这种问题?
Contributor guide
Assessment
This issue has not been assessed yet.