使用 angular $http 或 jquery.ajax 下载二进制文件时遇到问题
Trouble downloading binary file with angular $http or jquery.ajax
我的问题是我在客户端收到了错误大小的文件。这是我的@Controller ...
@RequestMapping(value = "/download/{id}", method = RequestMethod.GET)
public ResponseEntity<?> download(final HttpServletRequest request,
final HttpServletResponse response,
@PathVariable("id") final int id) throws IOException {
try {
// Pseudo-code for retrieving file from ID.
Path zippath = getZipFile(id);
if (!Files.exists(zippath)) {
throw new IOException("File not found.");
}
ResponseEntity<InputStreamResource> result;
return ResponseEntity.ok()
.contentLength(Files.size(zippath))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new InputStreamResource(new FileInputStream(zippath.toFile())));
} catch (Exception ex) {
// ErrorInfo is another class, unimportant
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorInfo(ex));
}
}
... 这是我使用 angular-file-saver ...
的客户端代码
$http({url: "export/download/" + exportitem.exportId, withCredentials: true})
.then(function(response) {
function str2bytes(str) {
var bytes = new Uint8Array(str.length);
for (var i=0; i<str.length; i++) {
bytes[i] = str.charCodeAt(i);
}
return bytes;
}
var blob = new Blob([str2bytes(response.data)], {type: 'application/octet-stream'});
FileSaver.saveAs(blob, "download.zip");
}, $exceptionHandler);
原始文件为 935673 字节,但 response.data 为 900728,将其通过转换为 Uint8Array 会生成大小为 900728 的 Blob。无论哪种方式,生成的保存文件都是 900728 字节(少 34945 字节)。所写的内容也不完全相同。它似乎有点臃肿,但最后一部分似乎被截断了。知道我可能做错了什么吗?
更新
我刚刚将我的控制器方法更新为以下内容并得到了完全相同的结果。呜呜呜
@RequestMapping(value = "/download/{id}", method = RequestMethod.GET)
public void download(final HttpServletRequest request,
final HttpServletResponse response,
@PathVariable("id") final int id) throws IOException {
// Pseudo-code for retrieving file from ID.
Path zippath = getZipFile(id);
if (!Files.exists(zippath)) {
throw new IOException("File not found.");
}
response.setContentType("application/zip");
response.setHeader("Content-Disposition",
"attachment; filename=download.zip");
InputStream inputStream = new FileInputStream(zippath.toFile());
org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
}
原来问题出在angular的$http服务上。我也尝试了 jQuery 的 ajax 方法。两者都给出了相同的结果。如果我改为使用本机 XMLHttpRequest,它可以正常工作。所以 Java 代码是合理的。我首先通过将文件直接公开到互联网来验证这一点,然后使用 curl 和直接在浏览器中访问我设法下载了正确大小的文件。然后我找到了这个解决方案,这样我也可以通过 javascript.
下载文件
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.withCredentials = true;
xhr.onreadystatechange = function (){
if (xhr.readyState === 4) {
var blob = xhr.response;
FileSaver.saveAs(blob, filename);
}
};
xhr.send();
为什么 angular 或 jQuery 给出了错误的结果?我仍然不知道,但如果有人希望给出使用这些答案的答案,我们将不胜感激。
我刚刚偶然发现了 $http 请求中的 'responseType',您可能正在寻找 'blob':https://docs.angularjs.org/api/ng/service/$http#usage
响应类型:blob
压缩文件的技巧
Angular 2 +
this.http.get('http://localhost:8080/export', { responseType: ResponseContentType.Blob })
.subscribe((res: any) => {
const blob = new Blob([res._body], { type: 'application/zip' });
saveAs(blob, "fileName.zip");
我的问题是我在客户端收到了错误大小的文件。这是我的@Controller ...
@RequestMapping(value = "/download/{id}", method = RequestMethod.GET)
public ResponseEntity<?> download(final HttpServletRequest request,
final HttpServletResponse response,
@PathVariable("id") final int id) throws IOException {
try {
// Pseudo-code for retrieving file from ID.
Path zippath = getZipFile(id);
if (!Files.exists(zippath)) {
throw new IOException("File not found.");
}
ResponseEntity<InputStreamResource> result;
return ResponseEntity.ok()
.contentLength(Files.size(zippath))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new InputStreamResource(new FileInputStream(zippath.toFile())));
} catch (Exception ex) {
// ErrorInfo is another class, unimportant
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorInfo(ex));
}
}
... 这是我使用 angular-file-saver ...
的客户端代码$http({url: "export/download/" + exportitem.exportId, withCredentials: true})
.then(function(response) {
function str2bytes(str) {
var bytes = new Uint8Array(str.length);
for (var i=0; i<str.length; i++) {
bytes[i] = str.charCodeAt(i);
}
return bytes;
}
var blob = new Blob([str2bytes(response.data)], {type: 'application/octet-stream'});
FileSaver.saveAs(blob, "download.zip");
}, $exceptionHandler);
原始文件为 935673 字节,但 response.data 为 900728,将其通过转换为 Uint8Array 会生成大小为 900728 的 Blob。无论哪种方式,生成的保存文件都是 900728 字节(少 34945 字节)。所写的内容也不完全相同。它似乎有点臃肿,但最后一部分似乎被截断了。知道我可能做错了什么吗?
更新
我刚刚将我的控制器方法更新为以下内容并得到了完全相同的结果。呜呜呜
@RequestMapping(value = "/download/{id}", method = RequestMethod.GET)
public void download(final HttpServletRequest request,
final HttpServletResponse response,
@PathVariable("id") final int id) throws IOException {
// Pseudo-code for retrieving file from ID.
Path zippath = getZipFile(id);
if (!Files.exists(zippath)) {
throw new IOException("File not found.");
}
response.setContentType("application/zip");
response.setHeader("Content-Disposition",
"attachment; filename=download.zip");
InputStream inputStream = new FileInputStream(zippath.toFile());
org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
}
原来问题出在angular的$http服务上。我也尝试了 jQuery 的 ajax 方法。两者都给出了相同的结果。如果我改为使用本机 XMLHttpRequest,它可以正常工作。所以 Java 代码是合理的。我首先通过将文件直接公开到互联网来验证这一点,然后使用 curl 和直接在浏览器中访问我设法下载了正确大小的文件。然后我找到了这个解决方案,这样我也可以通过 javascript.
下载文件var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.withCredentials = true;
xhr.onreadystatechange = function (){
if (xhr.readyState === 4) {
var blob = xhr.response;
FileSaver.saveAs(blob, filename);
}
};
xhr.send();
为什么 angular 或 jQuery 给出了错误的结果?我仍然不知道,但如果有人希望给出使用这些答案的答案,我们将不胜感激。
我刚刚偶然发现了 $http 请求中的 'responseType',您可能正在寻找 'blob':https://docs.angularjs.org/api/ng/service/$http#usage
响应类型:blob 压缩文件的技巧
Angular 2 +
this.http.get('http://localhost:8080/export', { responseType: ResponseContentType.Blob })
.subscribe((res: any) => {
const blob = new Blob([res._body], { type: 'application/zip' });
saveAs(blob, "fileName.zip");