java 不同浏览器 下载文件 有的浏览器会调两次后台
下面是javascript生成表单,调后台进行下载的代码:
var form = $("<form>");
form.attr("style", "display:none");
form.attr("target", "");
form.attr("method", "post");
form.attr("action", "download");
var input = $("<input>");
input.attr("type", "hidden");
input.attr("name", "downLoadInfo");
input.attr('value', selectedInfo);
$("body").append(form);
form.append(input);
form.submit()
下面是servlet中执行下载的主要方法:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
String downLoadInfo = request.getParameter("downLoadInfo");
String realPath = getServletContext().getRealPath("/").replaceAll("\\\\", "/");
Set<String> fileSet = this.getFileSet(downLoadInfo, realPath + "video/");
response.setContentType("text/plain");
response.setHeader("Location","video.zip");
response.setHeader("Content-Disposition", "attachment; filename=video.zip");
ZipOutputStream out = null;
FileInputStream scratchFileIs = null;
FileInputStream in = null;
try {
out = new ZipOutputStream(response.getOutputStream());
Iterator<String> iterator = fileSet.iterator();
byte[] buffer = new byte[5120];
out.putNextEntry(new ZipEntry("log.txt"));
scratchFileIs = this.writeScratchFile(downLoadInfo, realPath + "video/scratchFile/");
int scratchFileLength = 0;
while((scratchFileLength = scratchFileIs.read(buffer)) > 0) {
out.write(buffer, 0, scratchFileLength);
}
out.closeEntry();
scratchFileIs.close();
while(iterator.hasNext()) {
File file = new File(iterator.next());
in = new FileInputStream(file);
out.putNextEntry(new ZipEntry(file.getName()));
int length = 0;
while((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
out.closeEntry();
in.close();
}
out.flush();
out.close();
} catch (IOException e) {
BasicConfigurator.configure();
logger.error("",e);
throw e;
} finally {
if(in != null) {
in.close();
in = null;
}
if(scratchFileIs != null) {
scratchFileIs.close();
scratchFileIs = null;
}
if(out != null) {
out.close();
out = null;
}
}
}
private FileInputStream writeScratchFile(String downLoadInfo, String fileURL) throws IOException {
File file = new File(fileURL + new Date().getTime() + (int)(Math.random()*1000) + ".txt");
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
String[] allRecordString = downLoadInfo.split("<os>");
for(int i=0 ; i<allRecordString.length ; i++) {
String record = "";
record = allRecordString[i].replace("<rs>", ",");
record = record.replace("undefined", "");
bw.write(record.split("<filename>")[0]);
bw.newLine();
}
bw.flush();
bw.close();
FileInputStream scratchFileIs = new FileInputStream(file);
if(file.exists()) {
file.delete();
}
return scratchFileIs;
}
private Set<String> getFileSet(String downLoadInfo, String dirURL) {
Set<String> fileSet = new HashSet<String>();
String[] allRecordString = downLoadInfo.split("<os>");
for(int i=0 ; i<allRecordString.length ; i++) {
if(new File(dirURL + allRecordString[i].split("<filename>")[1]).exists()) {
fileSet.add(dirURL + allRecordString[i].split("<filename>")[1]);
}
}
return fileSet;
}
用搜狗浏览器下载执行javascript的方法会调用两次后台,导致报:
ClientAbortException: java.net.SocketException: Software caused connection abort: socket write error
这个异常,我写的代码中报此异常的是上面dopost方法中的红色标出位置。但是报这个异常不影响正常的下载。在网上查了很多资料,都没有对此异常很好的解决方法。现在查出的原因是,用搜狗浏览器进行下载,浏览器默认会选择搜狗下载器,用这个下载器就会调用两次后台,用IE浏览器或把搜狗浏览器的搜狗下载器关闭,将正常调用一次后台,并且不再抛出此异常。
问下各位大牛,对此有没有很好的解决办法。另外,是不是代码写的有问题,流没有很好的关闭。即使调用了两次servlet也不应该是抛出异常啊。