環境:Struts2.3.20 + Internet Exploer 11

程式:連結到專案內檔案的超連結
例如 <a href="file/template.xls">範本</a> 連結到 src/main/webapp/file 下的 template.xls

問題:用IE點選檔案「連結>開啟 (Excel/Word檔)」時,error log會列印出大量錯誤訊息
(可以正常下載並開啟檔案,使用者側感受不到錯誤,但背後的log會記錄錯誤)
(選「儲存」或「另存新檔」選項都沒問題,只有「開啟」的選項會出現錯誤)
(Firefox和Chrome不會發生這個問題,只有IE會)

錯誤訊息:
 Could not find action or result: /project/file/
 There is no Action mapped for action name file/. - [unknown location]
    at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
    at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:64)
    (以下省略)

 

看起來就是他把超連結當成struts2的action去解讀了,所以找不到mapping
但很神奇的就是要在IE+開啟的情況下才會發生,而且他會執行很多次 (出現好幾個同樣的長串錯誤訊息)

師傅說大概是IE的bug ... IE你可不可以問題不要那麼多!!!
理論上是個換瀏覽器就能解決的問題,但好無奈實際上大部分User都還是用IE 
他們根本不知道也不想知道"瀏覽器"是蝦米碗糕,無論怎樣宣導都不想換掉習慣的工具

解決方法:用downloadAction取代檔案的直接連結
一個既然你一定得把它當action那就做個action給你辨識吧的概念

jsp 裡改成連結到action,檔名當參數傳進去
<s:a action="download_downloadSystemFile"><s:param name="fileName">template.xls</s:param>範本</s:a>

DownloadAction.java 寫個對應的function

//import省略
public class DownloadAction extends ActionSupport {

    private InputStream inputStream;
    private String fileName;

    public String downloadSystemFile(){
        try{
            fileName=fileName;
            inputStream=this.getClass().getResourceAsStream("../../../../../file/"+fileName);
        }catch(Exception e){
            log.error("error",e);
        }
        return "file";
    }

   //inputStream和fileName的getter/setter省略
}

說明一下,那個 "../../../../../file/" 是相對路徑,假設package是aaa.bbb.ccc
class檔位於 project\target\classes\aaa\bbb\ccc
file檔位於 project\src\main\webapp\file,相對路徑就會變成這樣

然後return 的 "file" 對應,要去 struts.xml 加一個result type,重點是要設定成stream result
<result name="file" type="stream">
 <param name="contentDisposition">attachment;filename="${fileName}"</param>
</result>

如果確定是某種檔案可以再加 param
例如指定用Excel開啟 <param name="contentType">application/vnd.ms-excel</param>

這樣改使用者不會感受到有變化,而背後log不會再出現那個錯誤訊息 (雖然感覺工程有點大)


2016-06-20更新

雖然上面那個問題解決了,可是發現用IE6/8下載會出現另一個錯誤… …
觀察使用者的錯誤log發現一直以來常出現的這個錯誤只有在使用者用 IE6/8下載系統檔案的時候會出現

com.opensymphony.xwork2.util.logging.commons.CommonsLogger.error(CommonsLogger.java:42) Exception occurred during processing request: ServletException including path 'layout.jsp'.
org.apache.tiles.impl.CannotRenderException: ServletException including path '/layout.jsp'.
    at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:692)
    at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:644)
(中略)
Caused by: org.apache.tiles.util.TilesIOException: ServletException including path '/layout.jsp'.
    at org.apache.tiles.servlet.context.ServletUtil.wrapServletException(ServletUtil.java:241)
    at org.apache.tiles.servlet.context.ServletTilesRequestContext.include(ServletTilesRequestContext.java:262)

(中略)
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:564)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212)

其中那個 'layout.jsp' 是tiles的layout檔
自己電腦沒有IE6/8沒辦法測試,只知道IE11和chrome/FF一切正常
也不清楚使用者端有沒有下載成功、或有沒有看見什麼錯誤,目前無解

相关文章