{"record":{"id":"956a8d6b3117ac1d","repo":"YunaiV/yudao-cloud","slug":"path","errorCode":null,"errorMessage":"结尾的 path 路径必须传递","messagePattern":"结尾的 path 路径必须传递","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":500,"severity":"warning","filePath":"yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java","lineNumber":112,"sourceCode":"    @Parameter(name = \"ids\", description = \"编号列表\", required = true)\n    @PreAuthorize(\"@ss.hasPermission('infra:file:delete')\")\n    public CommonResult<Boolean> deleteFileList(@RequestParam(\"ids\") List<Long> ids) throws Exception {\n        fileService.deleteFileList(ids);\n        return success(true);\n    }\n\n    @GetMapping(\"/{configId}/get/**\")\n    @PermitAll\n    @TenantIgnore\n    @Operation(summary = \"下载文件\")\n    @Parameter(name = \"configId\", description = \"配置编号\", required = true)\n    public void getFileContent(HttpServletRequest request,\n                               HttpServletResponse response,\n                               @PathVariable(\"configId\") Long configId) throws Exception {\n        // 获取请求的路径\n        String path = StrUtil.subAfter(request.getRequestURI(), \"/get/\", false);\n        if (StrUtil.isEmpty(path)) {\n            throw new IllegalArgumentException(\"结尾的 path 路径必须传递\");\n        }\n        // 解码，解决中文、%、+ 等特殊字符路径的问题\n        // https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/\n        // https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/\n        path = HttpUtils.decodeUrlPath(path);\n\n        // 读取内容\n        byte[] content = fileService.getFileContent(configId, path);\n        if (content == null) {\n            log.warn(\"[getFileContent][configId({}) path({}) 文件不存在]\", configId, path);\n            response.setStatus(HttpStatus.NOT_FOUND.value());\n            return;\n        }\n        FileDO file = fileService.getFileByConfigIdAndPath(configId, path);\n        String filename = file != null && StrUtil.isNotEmpty(file.getName()) ? file.getName() : FileUtil.getName(path);\n        writeAttachment(response, filename, content);\n    }\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/YunaiV/yudao-cloud/blob/477be9dd49ab7223a972a6abdff0684d6423dec3/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java#L94-L130","documentation":"FileController.getFileContent maps GET /{configId}/get/** and extracts everything after '/get/' as the file path; if that substring is empty (request URI ends exactly at '/get/' — Spring still matches the /** wildcard), it throws IllegalArgumentException demanding the trailing path. The path is later URL-decoded, so a fully-encoded empty path also fails here.","triggerScenarios":"GET /admin-api/infra/file/{configId}/get/ with nothing after the slash; URL truncated by a client that strips a trailing slash's content (path ends '/get/'); constructing the URL from a null/empty file path variable.","commonSituations":"Template building the download URL from a DB field that is null/empty (e.g. avatar not yet uploaded); reverse proxy or frontend router normalizing away the path segment; manual testing hitting the bare endpoint.","solutions":["Append the actual file path after /get/: /admin-api/infra/file/{configId}/get/2024/08/avatar.png","Check the stored file URL/path field is non-empty before building the link","URL-encode the path properly (Chinese, %, +) so it survives proxies"],"exampleFix":"// before\nwindow.open(`/admin-api/infra/file/${configId}/get/`); // empty path\n\n// after\nwindow.open(`/admin-api/infra/file/${configId}/get/${encodeURIComponent(filePath)}`);","handlingStrategy":"validation","validationCode":"String path = StrUtil.subAfter(request.getRequestURI(), \"/get/\", false);\nif (StrUtil.isEmpty(path)) {\n    response.setStatus(400);\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never build download URLs from unchecked DB path fields — skip when empty","URL-encode the file path segment (Chinese, %, +)","Probe with a HEAD/GET and treat 400/404 as 'file not set' rather than crashing the UI"],"tags":["infra","file","download","validation","rest"],"backgroundTag":null,"analyzedSha":"477be9dd49ab7223a972a6abdff0684d6423dec3","analyzedAt":"2026-08-14T13:35:31.121Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}