Struts2 stream 結果類型下載檔案,中文檔名在瀏覽器顯示為 xxx.action 或亂碼。
HTTP Header Content-Disposition: attachment; filename="中文" 需 RFC 5987 編碼,否則瀏覽器回退解析導致截斷或誤判副檔名。
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${downloadFileName}"</param>
<param name="bufferSize">4096</param>
<param name="allowCaching">false</param>
</result>
public class DownloadAction extends ActionSupport {
private String downloadFileName; // getter/setter
private InputStream inputStream; // getter
public String execute() {
String originalName = "報表.xlsx";
try {
// RFC 5987: filename*=UTF-8''encoded
downloadFileName = java.net.URLEncoder.encode(originalName, "UTF-8")
.replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException e) {
downloadFileName = "download.xlsx";
}
inputStream = ServletActionContext.getServletContext()
.getResourceAsStream("/upload/" + originalName);
return SUCCESS;
}
}
| 瀏覽器 | 支援 | 備註 |
|---|---|---|
| Chrome/Firefox/Edge (新) | filename*=UTF-8'' | 標準支援 |
| IE / 舊版 Safari | filename="URLEncoder" | 需雙重寫法 |
HttpServletResponse resp = ServletActionContext.getResponse();
String ua = req.getHeader("User-Agent");
String encoded = URLEncoder.encode(originalName, "UTF-8").replace("+", "%20");
String headerValue;
if (ua.contains("MSIE") || ua.contains("Trident")) {
headerValue = "attachment; filename=\"" + encoded + "\"";
} else {
headerValue = "attachment; filename*=UTF-8''" + encoded;
}
resp.setHeader("Content-Disposition", headerValue);
若在 Struts2 中,可自訂 HttpHeaderResult 或在 execute() 直接操作 response (需返回 null)。