首页 > 解决方案 > Spring Boot 减少大型 CSV 文件的下载时间

问题描述

我有一个用于下载 CSV 文件的 API,该文件的大小可能很大(最大 15MB)。尽管响应时间相当长,但它在 Chrome 中给出了响应。但是,在 Safari 中,它会在 60 秒后显示 504 网关超时。这是代码:

public File dataToCSV(List<String[]> dataLines) throws IOException {

    File csvOutputFile = new File("supply_tracker_" + LocalDateTime.now() + ".csv");
    try (PrintWriter pw = new PrintWriter(csvOutputFile)) {
        dataLines.stream()
                .map(data -> String.join(",", data))
                .forEach(pw::println);
    }
    return csvOutputFile;
}

public ResponseEntity<Object> getFile(File csv) throws FileNotFoundException {
    if (csv != null) {
        InputStreamResource resource = new InputStreamResource(new FileInputStream(csv));
        long length = csv.length();
        boolean delete = csv.delete();
        if (delete) {
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", csv.getName()));
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(length)
                    .contentType(MediaType.parseMediaType("text/csv"))
                    .body(resource);
        }
    } else {
        return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
    }
    return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}

有什么方法可以减少响应时间?另外,是否有临时解决方案可以在 Safari 上进行这项工作?前端在 React 中,API 用于 axios 调用。

标签: javaspring-bootcsvspring-mvcresponse-time

解决方案


我建议使用ResponseBodyEmitter.

您在这里遇到的最大问题是您的客户端必须等待响应准备好 100%,然后服务器才能开始响应。

一旦这段等待时间超过读取超时(通常为 30 秒),您将收到超时错误。增加超时是一个非常短期的解决方案。

使用 ResponseBodyEmitter 允许您的服务器一次写入一行响应,因此初始响应要快得多。

另一个探索的途径是 Spring Reactive 库。我们的应用程序可以在 10、20 分钟内返回许多 GB,而不会出现问题。


推荐阅读