YunaiV/yudao-cloud · warning · IllegalArgumentException

结尾的 path 路径必须传递

Error message

结尾的 path 路径必须传递

What it means

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.

Source

Thrown at yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java:112

    @Parameter(name = "ids", description = "编号列表", required = true)
    @PreAuthorize("@ss.hasPermission('infra:file:delete')")
    public CommonResult<Boolean> deleteFileList(@RequestParam("ids") List<Long> ids) throws Exception {
        fileService.deleteFileList(ids);
        return success(true);
    }

    @GetMapping("/{configId}/get/**")
    @PermitAll
    @TenantIgnore
    @Operation(summary = "下载文件")
    @Parameter(name = "configId", description = "配置编号", required = true)
    public void getFileContent(HttpServletRequest request,
                               HttpServletResponse response,
                               @PathVariable("configId") Long configId) throws Exception {
        // 获取请求的路径
        String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false);
        if (StrUtil.isEmpty(path)) {
            throw new IllegalArgumentException("结尾的 path 路径必须传递");
        }
        // 解码,解决中文、%、+ 等特殊字符路径的问题
        // https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/807/
        // https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1432/
        path = HttpUtils.decodeUrlPath(path);

        // 读取内容
        byte[] content = fileService.getFileContent(configId, path);
        if (content == null) {
            log.warn("[getFileContent][configId({}) path({}) 文件不存在]", configId, path);
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return;
        }
        FileDO file = fileService.getFileByConfigIdAndPath(configId, path);
        String filename = file != null && StrUtil.isNotEmpty(file.getName()) ? file.getName() : FileUtil.getName(path);
        writeAttachment(response, filename, content);
    }

View on GitHub (pinned to 477be9dd49)

Solutions

  1. Append the actual file path after /get/: /admin-api/infra/file/{configId}/get/2024/08/avatar.png
  2. Check the stored file URL/path field is non-empty before building the link
  3. URL-encode the path properly (Chinese, %, +) so it survives proxies

Example fix

// before
window.open(`/admin-api/infra/file/${configId}/get/`); // empty path

// after
window.open(`/admin-api/infra/file/${configId}/get/${encodeURIComponent(filePath)}`);
Defensive patterns

Strategy: validation

Validate before calling

String path = StrUtil.subAfter(request.getRequestURI(), "/get/", false);
if (StrUtil.isEmpty(path)) {
    response.setStatus(400);
    return;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14). Data as JSON: /api/errors/956a8d6b3117ac1d. Report an issue: GitHub.