{"record":{"id":"7dbad02ee3951223","repo":"yudaocode/SpringBoot-Labs","slug":"id-7dbad0","errorCode":null,"errorMessage":"id 参数不允许为空","messagePattern":"id 参数不允许为空","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":200,"severity":"info","filePath":"labx-04-spring-cloud-alibaba-sentinel/labx-04-sca-sentinel-actuator-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java","lineNumber":69,"sourceCode":"            return \"执行成功\";\n        } catch (BlockException ex) { // <3>\n            return \"被拒绝\";\n        } finally {\n            // <4> 释放资源\n            if (entry != null) {\n                entry.exit();\n            }\n        }\n    }\n\n    // 测试「Sentinel @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":51,"sourceCodeEnd":85,"githubUrl":"https://github.com/yudaocode/SpringBoot-Labs/blob/6c12efaed06d12907a0f40dd2ad1f7020aec8798/labx-04-spring-cloud-alibaba-sentinel/labx-04-sca-sentinel-actuator-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java#L51-L85","documentation":"Intentional validation exception in the Sentinel lab (actuator variant). The /annotations_demo endpoint is annotated with @SentinelResource(blockHandler=..., fallback=...); when the optional `id` request parameter is omitted it is null and the method throws IllegalArgumentException. Sentinel's sentinel-resource annotation interceptor catches it and routes it to the fallback method, so the HTTP response is normally 'fallback：id 参数不允许为空' (200), not a 500 — the lab exists to demonstrate fallback routing.","triggerScenarios":"GET /demo/annotations_demo without the id query parameter. The IllegalArgumentException fires and the fallback function receives it as the Throwable parameter and returns its message.","commonSituations":"Testing the lab's fallback demo and forgetting the parameter; expecting a 400/validation error and being surprised by the 200 'fallback：...' body; confusing fallback (business exceptions) with blockHandler (flow/degrade BlockException) while learning Sentinel.","solutions":["Add the parameter: GET /demo/annotations_demo?id=1 to see the normal 'success...' response.","Read the 'fallback：...' body as proof the fallback path works — this is the demo's intended behavior.","To return a proper 400 instead, make the param required (@RequestParam Integer id) so Spring rejects missing values before the method body runs."],"exampleFix":"// before\n@GetMapping(\"/annotations_demo\")\npublic String annotationsDemo(@RequestParam(required = false) Integer id) {\n    if (id == null) {\n        throw new IllegalArgumentException(\"id 参数不允许为空\");\n    }\n    ...\n}\n\n// after — let Spring enforce presence; fallback stays for real business exceptions\n@GetMapping(\"/annotations_demo\")\npublic String annotationsDemo(@RequestParam Integer id) { ... }","handlingStrategy":"try-catch","validationCode":"// Simply include the required parameter\n// GET /demo/annotations_demo?id=1\nif (idParam == null) { /* don't call; pass id */ }","typeGuard":null,"tryCatchPattern":"// Client side: the server already routes this to Sentinel fallback (HTTP 200 body 'fallback：...')\nString body = restTemplate.getForObject(url + \"/annotations_demo?id={id}\", String.class, id);\nif (body.startsWith(\"fallback:\")) {\n    // handle degraded/business-failure path\n}","preventionTips":["Always send ?id=... when calling annotated demo endpoints.","Read Sentinel docs: fallback handles business exceptions, blockHandler handles BlockException.","Make required parameters required in @RequestParam so Spring returns 400."],"tags":["sentinel","spring-cloud-alibaba","tutorial-demo","fallback","validation"],"backgroundTag":null,"analyzedSha":"6c12efaed06d12907a0f40dd2ad1f7020aec8798","analyzedAt":"2026-08-14T13:06:31.500Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}