{"record":{"id":"569c82438a928eed","repo":"yudaocode/SpringBoot-Labs","slug":"id-569c82","errorCode":null,"errorMessage":"id 参数不允许为空","messagePattern":"id 参数不允许为空","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"lab-46/lab-46-sentinel-demo/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/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java#L49-L83","documentation":"The baseline Sentinel lab (no external config center): GET /demo/annotations_demo without id throws IllegalArgumentException('id 参数不允许为空'), and @SentinelResource(fallback=\"fallback\") routes it to the fallback method, returning 'fallback: id 参数不允许为空' with HTTP 200. Demonstrates Sentinel's exception-fallback mechanism in its simplest form.","triggerScenarios":"GET /demo/annotations_demo with no id on the plain sentinel-demo module. The blockHandler path triggers only under flow control (e.g., QPS rule on 'annotations_demo_resource'); this error is the fallback path.","commonSituations":"Canonical first-run Sentinel demo. Common confusion: developers see 'fallback: ...' and think a circuit breaker opened, when actually a plain business exception fired the fallback. Reverse confusion happens when they add a flow-control rule, hammer the endpoint, and still get the exception fallback because the resource name in the rule does not match value=\"annotations_demo_resource\".","solutions":["Use ?id=1 for the success path.","Remember: fallback = business exception path, blockHandler = Sentinel rule (BlockException) path; test them separately.","When testing blocking, make the rule's resource name exactly 'annotations_demo_resource' and exceed the configured QPS.","Fix parameter validation at the binding layer (required @RequestParam) if a 400 is preferred."],"exampleFix":"// before\npublic String annotationsDemo(@RequestParam(required = false) Integer id) {\n    if (id == null) throw new IllegalArgumentException(\"id 参数不允许为空\");\n    return \"success...\";\n}\n\n// after\npublic String annotationsDemo(@RequestParam Integer id) {\n    return \"success...\";\n}","handlingStrategy":"validation","validationCode":"public String annotationsDemo(@RequestParam Integer id) {\n    // Spring rejects a missing id with 400 before the method body runs\n    return \"success...\";\n}","typeGuard":null,"tryCatchPattern":"// Optional: use fallback to separate validation from degradation\npublic String fallback(Integer id, Throwable throwable) {\n    return throwable instanceof IllegalArgumentException\n        ? \"bad request\"\n        : \"degraded\";\n}","preventionTips":["Distinguish fallback (exception) from blockHandler (flow control) when testing Sentinel.","Enforce parameter presence via @RequestParam required attribute.","Match rule resource names to @SentinelResource value exactly."],"tags":["sentinel","circuit-breaker","fallback","parameter-validation","tutorial"],"backgroundTag":null,"analyzedSha":"6c12efaed06d12907a0f40dd2ad1f7020aec8798","analyzedAt":"2026-08-14T13:06:31.500Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}