{"record":{"id":"866a8f48f8e467f8","repo":"yudaocode/SpringBoot-Labs","slug":"id","errorCode":null,"errorMessage":"id 参数不允许为空","messagePattern":"id 参数不允许为空","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java","lineNumber":67,"sourceCode":"            return \"执行成功\";\n        } catch (BlockException ex) {\n            return \"被拒绝\";\n        } finally {\n            // 释放资源\n            if (entry != null) {\n                entry.exit();\n            }\n        }\n    }\n\n    // 测试 @SentinelResource 注解\n    @GetMapping(\"/annotations_demo\")\n    @SentinelResource(value = \"annotations_demo_resource\",\n            blockHandler = \"blockHandler\",\n            fallback = \"fallback\")\n    public String annotationsDemo(@RequestParam(required = false) Integer id) throws InterruptedException {\n        if (id == null) {\n            throw new IllegalArgumentException(\"id 参数不允许为空\");\n        }\n        return \"success...\";\n    }\n\n    // BlockHandler 处理函数，参数最后多一个 BlockException，其余与原函数一致.\n    public String blockHandler(Integer id, BlockException ex) {\n        return \"block：\" + ex.getClass().getSimpleName();\n    }\n\n    // Fallback 处理函数，函数签名与原函数一致或加一个 Throwable 类型的参数.\n    public String fallback(Integer id, Throwable throwable) {\n        return \"fallback：\" + throwable.getMessage();\n    }\n\n}\n","sourceCodeStart":49,"sourceCodeEnd":83,"githubUrl":"https://github.com/yudaocode/SpringBoot-Labs/blob/6c12efaed06d12907a0f40dd2ad1f7020aec8798/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java#L49-L83","documentation":"In the Sentinel + Apollo lab, GET /demo/annotations_demo throws IllegalArgumentException('id 参数不允许为空') when the id request parameter is omitted. The method is annotated @SentinelResource(fallback=\"fallback\"), so Sentinel routes the exception to the fallback(Integer id, Throwable) method, whose return value ('fallback: id 参数不允许为空') becomes the HTTP response instead of a 500. It demonstrates exception-based fallback (not flow-control blockHandler) in Sentinel.","triggerScenarios":"GET /demo/annotations_demo without ?id=1 — @RequestParam(required=false) yields null id, the null check throws, and the fallback function's string is returned.","commonSituations":"Verifying Sentinel fallback wiring. Common real mistakes: fallback method signature not matching (must match params plus optional Throwable), fallback/blockHandler placed in a different bean without blockHandlerClass/fallbackClass, or expecting fallback to also catch BlockException — it does when only fallback is configured (Throwable param catches it), but blockHandler takes precedence when both are set and the cause is a flow-control block.","solutions":["Call the endpoint with an id: /demo/annotations_demo?id=1 — this is the intended successful path.","If you want a 400 instead of the fallback string, validate the parameter earlier (e.g., @RequestParam(required=true)) or handle IllegalArgumentException in an @ControllerAdvice and exclude this resource from fallback.","Keep the fallback method public, in the same class (or referenced via fallbackClass), with the exact same parameter list (+ optional Throwable).","To distinguish degradation from business errors, configure blockHandler for BlockException and fallback for other Throwables as this demo does."],"exampleFix":"// before: optional param + manual null check routed to Sentinel fallback\npublic String annotationsDemo(@RequestParam(required = false) Integer id) {\n    if (id == null) {\n        throw new IllegalArgumentException(\"id 参数不允许为空\");\n    }\n    return \"success...\";\n}\n\n// after: let Spring enforce presence; no exception needed\npublic String annotationsDemo(@RequestParam Integer id) {\n    return \"success...\";\n}","handlingStrategy":"validation","validationCode":"// Caller-side: always pass the parameter.\n// GET /demo/annotations_demo?id=1\n// Server-side: enforce presence at binding time:\npublic String annotationsDemo(@RequestParam Integer id) { ... }","typeGuard":null,"tryCatchPattern":"// Not needed if fallback is configured; otherwise standard advice:\n@ExceptionHandler(IllegalArgumentException.class)\nCommonResult<?> badArg(IllegalArgumentException ex) {\n    return CommonResult.error(INVALID_PARAM, ex.getMessage());\n}","preventionTips":["Make required request params required=true so Spring returns 400 before your code runs.","Keep fallback/blockHandler signatures exactly matching the resource method (plus optional Throwable/BlockException).","Remember fallback handles business exceptions; blockHandler handles Sentinel BlockException."],"tags":["sentinel","circuit-breaker","fallback","parameter-validation","apollo","tutorial"],"backgroundTag":null,"analyzedSha":"6c12efaed06d12907a0f40dd2ad1f7020aec8798","analyzedAt":"2026-08-14T13:06:31.500Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}