最近一个重构的系统上线后客户发现无法使用IE6下载报表,具体为能弹出“另存为”对话框,但没有显示报表名称,点击保存后报错,无法下载。但是在我的WIN7笔记本上使用IE9和Firefox均能正常下载,使用同事的WIN7下的搜狗浏览器也可以正确下载。由于我将项目的Spring版本从3.0.5.RELEASE升级到了3.1.0.RC1,所以一度以为是由于Spring框架内部的问题,但是在对比的新旧代码后发现问题不在这,新版本的代码中多了一个检测session超时的拦截器,其中有段关键代码:
response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", -1);
为什么要这样写参见我的这篇博文。
先简单说一下我们的报表导出原理,我们采用在Excel上画好模版,另存为“xml模版”,然后将xml的内容复制到jsp文件内,添加jstl支持使jsp文件动态化,用户访问一个url时,control端处理完毕后执行
response.setHeader("Content-Disposition", "attachment; filename=测试报表.xls");
使用户浏览器弹出一个另存为对话框,保存后就将这个jsp文件变成了后缀名为xls的excel文件(其实本质还是一个文本文件)。
回到导出报表上,通过jmeter工具发送url请求后的取样器结果中包含这样一段:
Thread Name: 线程组 1-1 Sample Start: 2011-10-26 13:38:23 CST Load time: 5253 Latency: 31 Size in bytes: 12414200 Sample Count: 1 Error Count: 0 Response code: 200 Response message: OK Response headers: HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Expires: Thu, 01-Jan-1970 00:00:00 GMT Content-Disposition: attachement; filename=excel.xls Content-Language: zh-CN Content-Type: application/vnd.ms-excel;charset=gb2312 Set-Cookie: JSESSIONID=e1uhcjpgko27zheg3bfajw6y;Path=/lmkweb Transfer-Encoding: chunked Server: Jetty(7.2.0.v20101020) HTTPSampleResult fields: ContentType: application/vnd.ms-excel;charset=gb2312 DataEncoding: gb2312
去掉拦截器的no-cache这段代码后,在IE6中就能正确下载了,所以初步认为是response的header中的Cache-Control和Content-Disposition冲突了(IE6,IE7等等),但是底层细节不甚明了(WIN7的IE9和Firefox没有问题)。
另:在写测试代码时发现一个以前就想知道原因的现象,即如果这个报表文件非常小,IE的另存为对话框弹出后会显示字节数,而如果非常大,等一会儿弹出的对话框不显示字节数,在下载的过程中会显示下载了多少,下载速度等等。
这次在测试的jsp文件中加入了
<% for (int i = 0; i < 10000; i++) { System.out.println("[" + i + "]"); %> ... <% } %>
在浏览器中测试发现,在控制台打印到70左右时便不再输出了,而页面就弹出另存为对话框,点击保存后,控制台又开始打印。而在jmeter测试中不存在这种暂停。所以初步认为浏览器保存jsp文件时应该有一种缓存机制,非常有意思。