【问题标题】:Java spring file download proxy with rest calls带有休息调用的Java spring文件下载代理
【发布时间】:2018-01-11 16:34:45
【问题描述】:

我需要在 java 中创建一个 rest 服务,它会连接到另一个 rest 服务以进行文件下载。目前,我只需要将文件从另一个后端传输到客户端,但将来会进行一些处理/转换。

对于我项目中的所有 Web 服务,我们使用的是 spring rest(用于提供和使用服务)。

我的问题是,考虑到文件很大并且我不想遇到 OutOfMemory 错误,这样做的适当方法是什么。

其他一些帖子中的人建议在两端都使用流,但这真的可能吗?为此,我需要先将文件写入磁盘吗?

我当前的文件下载代码(消费者) -

public BackendResponse<byte[]> callBackendForFile(BackendRequest request) {

        String body = null;
        ResponseEntity<byte[]> responseEntity = null;
        URI uri = createURI(request);

        MultiValueMap<String, String> requestHeaders = getHeadersInfo(request.getHttpRequest());

        if (HttpMethod.GET.equals(request.getMethod())) {
            responseEntity = restTemplate.exchange(uri, request.getMethod(),
                    new HttpEntity<String>(body, requestHeaders), byte[].class);
        } else {
            LOG.error("Method:{} not supported yet", request.getMethod());
        }

        BackendResponse<byte[]> response = new BackendResponse<>();
        response.setResponse(responseEntity);
        return response;

    }

我的客户代码(提供者):

@RequestMapping(value = "/file", method = RequestMethod.GET, produces = "application/xml")
    @ResponseBody
    public void downloadFileWithoutSpring(HttpMethod method, HttpServletRequest httpRequest,
            HttpServletResponse httpResponse) {

        BackendRequest request = new BackendRequest(method,
                httpRequest.getRequestURI(), httpRequest.getQueryString(), httpRequest);

        BackendResponse<byte[]> backendResponse = dutyplanService.getFile(request);
        ResponseEntity<byte[]> response = backendResponse.getResponse();

        httpResponse.addHeader("Content-Disposition", "attachment; filename=\"" + "attachment.zip" + "\"");
        httpResponse.getOutputStream().write(response.getBody());
        httpResponse.flushBuffer();
}

注意:上面的代码不起作用,因为下载的附件是损坏的文件

【问题讨论】:

  • RestTemplate 默认会将所有文件作为 byte[] 复制到内存中。 为避免 OutOfMemory 异常,您应该使用流 - 因此您的客户端使用响应中的 InputStream 并将其写入 httpResponse.getOutputStream()Here你可以找到一个巧妙的解决方案。
  • 您找到解决方案了吗?如果是这样,请告诉我。我也有类似的情况。
  • 如果有人在寻找解决方案,请点击此处:stackoverflow.com/questions/47277640/…

标签: java file proxy resttemplate spring-rest


【解决方案1】:

我认为你不需要在服务器上创建该文件,只要你从另一台服务器接收到它的字节数组内容。

您可以尝试将生成注释的值更改为值application/zip(或application/octet-stream,取决于目标浏览器)而不是'application/xml'

【讨论】:

  • 不知何故,即使更改生产注释也不起作用。此外,在字节数组中有完整的文件意味着整个文件在内存中,如果文件很大,例如100 MB 然后这一切都将在内存中......
  • 该服务器是否可以从外部网络访问?如果是,您可以直接返回该文件的 URL,并且在任何事件(下载点击)上,您都可以点击该 URL 下载文件。
  • @RohanKadu 有时与我的公司相同,每个人都无法访问服务器,我们强制使用应用程序代理数据。
【解决方案2】:

你可以直接在restTemplate中传递HttpServletResponse#getOutputStream(),不用在服务器中保存文件就可以写入。

public void getFile(HttpServletResponse response) throws IOException {
        restTemplate.execute(
                "http://ip:port/temp.csv",
                HttpMethod.GET,
                null,
                clientHttpResponse -> {
                    StreamUtils.copy(clientHttpResponse.getBody(), response.getOutputStream());
                    return null;
                }
        );
    }

请注意,在调用getFile() 之后,您应该像这样关闭 outputStream response.getOutputStream().close()

【讨论】:

    猜你喜欢
    • 2016-03-22
    • 1970-01-01
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多