You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot下载PDF触发HttpMediaTypeNotAcceptableException问题解析

异常原因解析

核心问题:错误配置了consumes属性

  1. @GetMapping的consumes属性作用是限定请求体的媒体类型,但GET请求本身通常不携带请求体,这个配置从场景上就不适用。
  2. 当你设置consumes = MediaType.APPLICATION_JSON_VALUE时,Spring MVC会强制要求请求的Content-Type为application/json,但你测试时的GET请求大概率没有携带这个请求头(也不应该携带)。
  3. 同时你的请求设置了Accept: application/pdf,此时Spring的内容协商机制会陷入矛盾:一方面接口要求请求体是JSON(但实际没有),另一方面找不到能将byte[]转换为application/pdf的合适消息转换器,最终抛出HttpMediaTypeNotAcceptableException。

简单说就是:你给GET接口加了一个只针对带请求体的POST/PUT等请求的配置,直接打乱了Spring的请求匹配和响应处理逻辑。

两种实现方式的差异

方式一:ResponseEntity<byte[]>(正确配置后)

  • 基于Spring MVC的封装特性,通过ResponseEntity统一管理响应状态码、响应头和响应体
  • 正确用法不需要consumes,只需在响应中指定正确的Content-Type:
@GetMapping("/download-pdf")
public ResponseEntity<byte[]> downloadPdf() {
    // 生成PDF字节流的逻辑
    byte[] pdfContent = generatePdf();
    return ResponseEntity.ok()
            .contentType(MediaType.APPLICATION_PDF)
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"document.pdf\"")
            .body(pdfContent);
}
  • 优势:符合Spring MVC的规范,能和框架的其他特性(如全局异常处理、拦截器)无缝配合,代码更简洁易维护。

方式二:直接操作HttpServletResponse

  • 绕开Spring MVC的消息转换器和内容协商机制,直接通过原生Servlet API写入响应流
  • 典型写法:
@GetMapping("/download-pdf")
public void downloadPdf(HttpServletResponse response) throws IOException {
    byte[] pdfContent = generatePdf();
    response.setContentType(MediaType.APPLICATION_PDF_VALUE);
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"document.pdf\"");
    response.getOutputStream().write(pdfContent);
    response.getOutputStream().flush();
}
  • 优势:能对响应做更精细化的控制(比如自定义流的写入逻辑);劣势:脱离Spring MVC的封装,无法利用框架的统一处理能力,代码相对繁琐。

内容的提问来源于stack exchange,提问作者phildeg31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:12:37