如何使用 Jersey 从服务器发送大文件?
How to send a large file from server using Jersey?
我正在尝试下载并保存一个大的 zip 文件。 zip 文件可能比堆大,所以我想使用流来避免 java.lang.OutOfMemoryError: Java heap space
错误。
另外,大zip文件是应要求生成的,所以我想下载后删除该文件。
我当前的代码是
@POST
@Path("/downloadLargeZip")
public Response largeZip() throws FileNotFoundException {
File file = generateZipFile(); // generates zip file successfully
FileInputStream input = new FileInputStream(file);
StreamingOutput so = os -> {
try {
int n;
byte[] buffer = new byte[1024];
while ((n = input.read(buffer)) >= 0) {
os.write(buffer, 0, n);
}
os.flush();
os.close();
} catch (Exception e) {
throw new WebApplicationException(e);
}
};
return Response.ok(so).build();
}
我当前的client-side代码是
import { saveAs } from 'browser-filesaver/FileSaver.js';
save() {
this.http.post<any>('url', '', { observe: 'response', responseType: 'blob'})
.subscribe(res => {
this.downloadFile(res);
});
}
downloadFile(response: any) {
const contentDisposition = 'attachment; filename="KNOWN_FILE_NAME"'; // response.headers('content-disposition'); - response object has no headers
// Retrieve file name from content-disposition
let fileName = contentDisposition.substr(contentDisposition.indexOf('filename=') + 9);
fileName = fileName.replace(/\"/g, '');
const contentType = 'application/zip'; // response.headers('content-type');
const blob = new Blob([response.data], { type: contentType });
saveAs(blob, fileName);
}
我的代码有一些问题:
- 使用开发工具检查响应,它没有 headers(
normalizedNames
是一个没有条目的映射)或数据。
- 正在检查保存的zip 文件,我无法使用WinRAR 打开它。错误是
The archive is either in unknown format or damaged
.
- 正在尝试用Notepad++打开zip文件,内容是文本
undefined
。
响应的JSON表示是
{
"headers":{
"normalizedNames":{
},
"lazyUpdate":null
},
"status":200,
"statusText":"OK",
"url":"URL",
"ok":true,
"type":4,
"body":{
}
}
尽管 body
确实包含数据 {size: 2501157, type: "application/json"}
。
请忽略数字(我猜这是 zip 文件的字节大小,实际文件会大得多)。
我做错了什么?如何读取流并保存生成的 zip 文件?
我认为问题出在我的 downloadFile
函数中,但我不知道要在那里更改什么。
如有任何帮助,我们将不胜感激。
我需要彻底改变处理问题的方式。
服务器现在将为客户端生成文件和 return URI。然后客户端将通过给定的 URI 下载文件。
服务器代码
@POST
@Path("/create")
public Response createLogs(String data) {
String fileName = generateFileAndReturnName(data);
if (fileName != null) {
return Response.created(URI.create(manipulateUri(fileName))).build();
}
return Response.status(500).build();
}
客户代码
save() {
this.http.post<any>(this.baseUrl + '/create', this.data, { observe: 'response'}).subscribe(postResponse => {
if (postResponse.status !== 201) {
this.logger.error('Failed.');
return;
}
postResponse.headers.keys(); // lazy init headers
const uri = postResponse.headers.get('location');
if (!uri) {
this.logger.error('URI not present.');
return;
}
const link = document.createElement('a');
link.href = uri;
link.setAttribute('download', 'fileName.fileExtension');
document.body.appendChild(link);
link.click();
if (link.parentNode) {
link.parentNode.removeChild(link);
}
});
}
现在使用 40GB 文件(32GB RAM,因此文件肯定比任何分配的堆都大)工作正常。
我正在尝试下载并保存一个大的 zip 文件。 zip 文件可能比堆大,所以我想使用流来避免 java.lang.OutOfMemoryError: Java heap space
错误。
另外,大zip文件是应要求生成的,所以我想下载后删除该文件。
我当前的代码是
@POST
@Path("/downloadLargeZip")
public Response largeZip() throws FileNotFoundException {
File file = generateZipFile(); // generates zip file successfully
FileInputStream input = new FileInputStream(file);
StreamingOutput so = os -> {
try {
int n;
byte[] buffer = new byte[1024];
while ((n = input.read(buffer)) >= 0) {
os.write(buffer, 0, n);
}
os.flush();
os.close();
} catch (Exception e) {
throw new WebApplicationException(e);
}
};
return Response.ok(so).build();
}
我当前的client-side代码是
import { saveAs } from 'browser-filesaver/FileSaver.js';
save() {
this.http.post<any>('url', '', { observe: 'response', responseType: 'blob'})
.subscribe(res => {
this.downloadFile(res);
});
}
downloadFile(response: any) {
const contentDisposition = 'attachment; filename="KNOWN_FILE_NAME"'; // response.headers('content-disposition'); - response object has no headers
// Retrieve file name from content-disposition
let fileName = contentDisposition.substr(contentDisposition.indexOf('filename=') + 9);
fileName = fileName.replace(/\"/g, '');
const contentType = 'application/zip'; // response.headers('content-type');
const blob = new Blob([response.data], { type: contentType });
saveAs(blob, fileName);
}
我的代码有一些问题:
- 使用开发工具检查响应,它没有 headers(
normalizedNames
是一个没有条目的映射)或数据。 - 正在检查保存的zip 文件,我无法使用WinRAR 打开它。错误是
The archive is either in unknown format or damaged
. - 正在尝试用Notepad++打开zip文件,内容是文本
undefined
。
响应的JSON表示是
{
"headers":{
"normalizedNames":{
},
"lazyUpdate":null
},
"status":200,
"statusText":"OK",
"url":"URL",
"ok":true,
"type":4,
"body":{
}
}
尽管 body
确实包含数据 {size: 2501157, type: "application/json"}
。
请忽略数字(我猜这是 zip 文件的字节大小,实际文件会大得多)。
我做错了什么?如何读取流并保存生成的 zip 文件?
我认为问题出在我的 downloadFile
函数中,但我不知道要在那里更改什么。
如有任何帮助,我们将不胜感激。
我需要彻底改变处理问题的方式。
服务器现在将为客户端生成文件和 return URI。然后客户端将通过给定的 URI 下载文件。
服务器代码
@POST
@Path("/create")
public Response createLogs(String data) {
String fileName = generateFileAndReturnName(data);
if (fileName != null) {
return Response.created(URI.create(manipulateUri(fileName))).build();
}
return Response.status(500).build();
}
客户代码
save() {
this.http.post<any>(this.baseUrl + '/create', this.data, { observe: 'response'}).subscribe(postResponse => {
if (postResponse.status !== 201) {
this.logger.error('Failed.');
return;
}
postResponse.headers.keys(); // lazy init headers
const uri = postResponse.headers.get('location');
if (!uri) {
this.logger.error('URI not present.');
return;
}
const link = document.createElement('a');
link.href = uri;
link.setAttribute('download', 'fileName.fileExtension');
document.body.appendChild(link);
link.click();
if (link.parentNode) {
link.parentNode.removeChild(link);
}
});
}
现在使用 40GB 文件(32GB RAM,因此文件肯定比任何分配的堆都大)工作正常。