【问题标题】:HttpServletResponse.addHeader() and setHeader() not working in Spring ControllerHttpServletResponse.addHeader() 和 setHeader() 在 Spring Controller 中不起作用
【发布时间】:2014-06-24 20:37:45
【问题描述】:

我正在尝试使用 spring-mvc、spring-boot 和 spring security 构建一个小型 Web 应用程序。仅使用一个控制器,服务端点之一是让用户下载由 Web 应用程序生成的 docx 文件。我的逻辑代码运行良好,问题是当我想将Headers添加到HttpServletResponse时,addHeader()和setHeader()不起作用,我只想为下载文件指定一个名称。我打印了一些日志,但不知道为什么这不起作用。

这是我的控制器的部分代码:

@Controller
public class ImportExportController {

    private final static Logger LOGGER = LoggerFactory.getLogger(ImportExportController.class);

    @Autowired
    private WordProcessor wordProcessor;

    @RequestMapping("/export")
    public void export(@RequestParam(value = "domainName", required = true) String domainName,
                       @RequestParam(value = "projectName", required = true) String projectName,
                       @RequestParam(value = "testFolderId", required = true) int testFolderId,
                       HttpServletRequest request, HttpServletResponse response) {

        String exportedFileName = "exportedTC_" + domainName + "_" + projectName + "_"
                + Integer.toString(testFolderId) + ".docx";

        try {
            extendExpiredALMSession();
            SaveToZipFile saver = wordProcessor.ExportToWord(domainName, projectName,
                                                             Integer.toString(testFolderId));
            saver.save(response.getOutputStream());
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            LOGGER.info("exportedFileName: " + exportedFileName);
            LOGGER.info("contains: " + response.containsHeader("Content-Disposition"));
            response.addHeader("Content-Disposition", "attachment; filename=\"" + exportedFileName + "\"");
            for (String name : response.getHeaderNames()) {
                LOGGER.info("Header: " + name);
            }
            LOGGER.info("Date Header:" + response.getHeader("Date"));
            LOGGER.info("Content-Disposition header: " + response.getHeader("Content-Disposition"));
            LOGGER.info("ContentType: " + response.getHeader("ContentType"));
            response.flushBuffer();
        } catch (RequestFailureException | RESTAPIException | InvalidDataException | UnLoginException
                | UnAuthorizedOperationException | IOException | Docx4JException | URISyntaxException e) {
            e.printStackTrace();
        }
    }
}

这是我得到的日志,你可以看到标题“Content-Disposition”和“ContentType”都是空的。

2014-05-07_13:35:05.646 INFO  c.c.p.a.w.w.ImportExportController - exportedFileName: exportedTC_DEFAULT_JIRA_Test_CPL5_4520.docx
2014-05-07_13:35:05.646 INFO  c.c.p.a.w.w.ImportExportController - contains: false
2014-05-07_13:35:05.646 INFO  c.c.p.a.w.w.ImportExportController - Header: X-Content-Type-Options
2014-05-07_13:35:05.646 INFO  c.c.p.a.w.w.ImportExportController - Header: X-XSS-Protection
2014-05-07_13:35:05.646 INFO  c.c.p.a.w.w.ImportExportController - Header: Cache-Control
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: Pragma
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: Expires
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: X-Frame-Options
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: X-Application-Context
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: Transfer-Encoding
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Header: Date
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Date Header:Wed, 07 May 2014 17:35:05 GMT
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - Content-Disposition header: null
2014-05-07_13:35:05.647 INFO  c.c.p.a.w.w.ImportExportController - ContentType: null

感谢阅读。任何帮助将不胜感激。

【问题讨论】:

  • 可能是因为直到response.flushBuffer(); 他们还没有真正写入响应?
  • 我认为在那之前它都在缓冲区中,而不一定在对象本身的成员中。

标签: spring spring-mvc servlets httpresponse


【解决方案1】:

事实证明,Spring Controller 对所有响应都有默认标头,因此我可以访问响应正文,但不能访问标头。要设置 HttpHeaders,返回一个 HttpEntity 即可。解决方案代码如下:

  @RequestMapping(value = "/export", method = RequestMethod.GET, produces = "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
    public HttpEntity<byte[]> export(@RequestParam(value = "domainName", required = true) String domainName,
                                     @RequestParam(value = "projectName", required = true) String projectName,
                                     @RequestParam(value = "testFolderId", required = true) int testFolderId) {

    String exportedFileName = "exportedTC_" + domainName + "_" + projectName + "_"
            + Integer.toString(testFolderId) + ".docx";
    SaveToZipFile saver = null;
    ByteArrayOutputStream out = null;
    HttpHeaders responseHeaders = null;
    byte[] documentBody = null;
    try {
        extendExpiredALMSession();
        saver = wordProcessor.ExportToWord(domainName, projectName, Integer.toString(testFolderId));
        out = new ByteArrayOutputStream();
        saver.save(out);
        responseHeaders = new HttpHeaders();
        responseHeaders.add("Content-Type",
                            "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        responseHeaders.add("Content-Disposition", "attachment; filename=\"" + exportedFileName + "\"");
        documentBody = out.toByteArray();
    } catch (RequestFailureException | RESTAPIException | InvalidDataException | UnLoginException
            | UnAuthorizedOperationException | IOException | Docx4JException | URISyntaxException e) {
        e.printStackTrace();
    }
    return new HttpEntity<byte[]>(documentBody, responseHeaders);
    }

这对我有用。

【讨论】:

    【解决方案2】:

    今天我也遇到了与这里描述的完全相同的问题。我仔细观察了一下,在this tutorial 中发现必须在内容之前设置标题。然后我换了台词,一切都很顺利,就像一个魅力。

    在你的情况下,我建议推线 saver.save(response.getOutputStream()); 之前 response.flushBuffer(); 在所有标头都已设置之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多