针对微服务项目中临时挂起接口的需求,以下是几种常见的实现方案:

一、配置中心方案(推荐)

1. 基于Spring Cloud Config/Nacos/Apollo

@Component
@RefreshScope
public class ApiSwitchConfig {
    @Value("${api.switch.sampleApi:true}")
    private Boolean sampleApiEnabled;
    
    public Boolean isSampleApiEnabled() {
        return sampleApiEnabled;
    }
}

@RestController
@RequestMapping("/api")
public class SampleController {
    @Autowired
    private ApiSwitchConfig apiSwitchConfig;
    
    @GetMapping("/sample")
    public ResponseEntity<?> sampleApi() {
        if (!apiSwitchConfig.isSampleApiEnabled()) {
            return ResponseEntity.status(503)
                .body(new ApiResponse(503, "接口维护中,请稍后重试"));
        }
        // 正常业务逻辑
        return ResponseEntity.ok("success");
    }
}

2. 通过Actuator端点动态更新

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: refresh, apiswitch
@RestController
@RequestMapping("/manage")
@RefreshScope
public class ApiSwitchController {
    private Map<String, Boolean> apiSwitchMap = new ConcurrentHashMap<>();
    
    @PostMapping("/switch/{apiName}")
    public String switchApi(@PathVariable String apiName, 
                          @RequestParam Boolean enabled) {
        apiSwitchMap.put(apiName, enabled);
        return "接口" + apiName + (enabled ? "已启用" : "已禁用");
    }
    
    public boolean isApiEnabled(String apiName) {
        return apiSwitchMap.getOrDefault(apiName, true);
    }
}

二、API网关方案

1. Spring Cloud Gateway 过滤器

@Component
public class ApiDisableFilter implements GlobalFilter, Ordered {
    @Autowired
    private ApiSwitchService switchService;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().value();
        
        if (switchService.isDisabled(path)) {
            exchange.getResponse().setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
            exchange.getResponse().getHeaders()
                   .add("Content-Type", "application/json");
            
            String body = "{\"code\":503,\"msg\":\"接口维护中\"}";
            DataBuffer buffer = exchange.getResponse()
                .bufferFactory().wrap(body.getBytes());
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }
}

2. Nginx配置

location /api/sample {
    # 临时返回503
    return 503 '{"code": 503, "msg": "服务维护中"}';
    
    # 或者重写到维护页面
    # rewrite ^ /maintenance.html break;
    
    # 或者限制特定IP访问
    # allow 192.168.1.0/24;
    # deny all;
}

三、数据库控制方案

@Service
public class ApiSwitchService {
    @Autowired
    private ApiSwitchRepository switchRepository;
    
    // 接口开关缓存
    private Cache<String, Boolean> apiSwitchCache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.SECONDS)
        .build();
    
    public boolean isApiEnabled(String apiPath) {
        try {
            return apiSwitchCache.get(apiPath, () -> {
                ApiSwitchConfig config = switchRepository.findByApiPath(apiPath);
                return config == null || config.isEnabled();
            });
        } catch (Exception e) {
            return true; // 降级处理
        }
    }
    
    @Scheduled(fixedDelay = 30000) // 30秒同步一次
    public void syncApiSwitch() {
        apiSwitchCache.invalidateAll();
    }
}

@Entity
@Table(name = "api_switch_config")
public class ApiSwitchConfig {
    @Id
    private Long id;
    private String apiPath;
    private Boolean enabled = true;
    private String remark;
    private Date disableStartTime;
    private Date disableEndTime;
}

四、AOP切面方案

@Aspect
@Component
public class ApiSwitchAspect {
    @Autowired
    private ApiSwitchService apiSwitchService;
    
    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void apiOperation() {}
    
    @Around("apiOperation()")
    public Object aroundApi(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String apiPath = getApiPath(signature.getMethod());
        
        if (!apiSwitchService.isApiEnabled(apiPath)) {
            throw new ApiDisabledException("接口暂时不可用");
        }
        return joinPoint.proceed();
    }
    
    private String getApiPath(Method method) {
        RequestMapping classMapping = method.getDeclaringClass()
            .getAnnotation(RequestMapping.class);
        RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);
        return (classMapping.value()[0] + methodMapping.value()[0])
            .replace("//", "/");
    }
}

五、运维层面方案

1. Kubernetes Pod标签选择

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
      version: v1.0
      # 通过修改标签临时摘除流量
      # enabled: "false" 
  template:
    metadata:
      labels:
        app: user-service
        version: v1.0
        enabled: "true"

2. Istio流量管理

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: user-service-route
spec:
  hosts:
  - user-service
  http:
  - match:
    - uri:
        prefix: /api/sample
    fault:
      abort:
        percentage:
          value: 100.0
        httpStatus: 503

六、综合管理平台方案

@RestController
@RequestMapping("/admin/api-switch")
public class ApiSwitchAdminController {
    
    @PostMapping("/disable")
    public Result disableApi(@RequestBody DisableApiRequest request) {
        // 1. 更新数据库
        apiSwitchService.disableApi(request.getApiPath(), 
            request.getReason(), 
            request.getEndTime());
        
        // 2. 通知配置中心刷新
        configService.publishConfig("API_SWITCH", buildConfig());
        
        // 3. 刷新网关路由
        gatewayService.refreshRoutes();
        
        // 4. 记录操作日志
        logService.logOperation("disable_api", request);
        
        // 5. 发送通知
        notifyService.sendMaintenanceNotice(request);
        
        return Result.success();
    }
    
    @Data
    public static class DisableApiRequest {
        private String apiPath;
        private String reason;
        private Date endTime;
        private String operator;
        private List<String> notifyChannels; // 通知渠道
    }
}

选择建议

  1. 快速临时关闭:使用API网关或Nginx配置

  2. 精确控制:使用配置中心 + 应用内检查

  3. 长期维护:数据库方案 + 管理平台

  4. 云原生环境:Kubernetes + Istio

  5. 需要审计:数据库方案 + 操作日志

最佳实践

  • 提供友好的维护页面

  • 设置合理的超时时间

  • 支持灰度恢复

  • 保留操作日志

  • 多渠道通知(钉钉、邮件、短信)

  • 自动恢复机制(避免忘记开启)

更多推荐