与 excel 文件的内容协商失败

Unsuccessful content negotation with excel file

我有一个 Spring 引导应用程序,它有一个已经可以生成 xlsx 文件的工作端点。 现在,我想在此端点上实施内容协商,但我总是收到 406 Not Acceptable.

{
    "timestamp": "2021-03-09T18:44:56.997+0000",
    "status": 406,
    "error": "Not Acceptable",
    "message": "Could not find acceptable representation",
    "path": "/students/excel"
}

我正在使用 URL 参数,我是这样称呼它的

localhost:8080/students/excel/excel?format=xlsx

实施

端点

    @PostMapping(path = "/excel", produces = {"application/vnd.ms-excel"})
    public byte[] generateExcel(HttpServletResponse response, final @RequestBody @NonNull Criteria criteria) {
            
        response.setContentType("application/vnd.ms-excel");

        response.setHeader("Content-Disposition", "attachment; filename=Students.xlsx");

        return studentService.generateExcelReport(response, criteria);
    }

正在完成 excel 文件的方法。

   public static byte[] write(HttpServletResponse response, final @NonNull XSSFWorkbook workbook) {
        
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            os.writeTo(response.getOutputStream());
            workbook.write(os);
            workbook.close();
            return os.toByteArray();
        } catch (final IOException ex) {
            throw new RuntimeException("Error generating excel", ex);
        }
    }

以及 WebConfiguration 上实现 WebMvcConfigurer

的相关方法
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

        configurer.favorPathExtension(false).
                        favorParameter(true).
                        parameterName("format").
                        ignoreAcceptHeader(true).
                        useJaf(false).
                defaultContentType(MediaType.APPLICATION_JSON).
                mediaType("xlsx", MediaType.MULTIPART_FORM_DATA);
    }

我尝试了很多 MediaTypeWebConfiguration 的组合以及 produces 的属性,比如 application/csv 检查是否有可能由于 excel 文件和其他文件的格式而工作。但是我无法克服这种状态。将其设置为 application/jsontext/plain 时它可以工作,但它不是所需的功能或正确的功能。

当我不使用内容协商时,excel 的生成就像我提到的那样工作。

编辑: 根据建议,我将内容类型更改为 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 并在 Postman 上更改了 AcceptContent-Type 的 header 并且仍然收到 406.

这是 Postman 上的请求的样子

我也调试了应用程序,它没有进入端点的方法,它似乎因为生成值而立即失败。

我想补充一点,这是一个接受 JSON 的 POST 请求。因此,在 Postman 上使用任何其他 content-type 都会破坏它。

更新

它通过使用接受 header 而不是参数并更改 WebConfigurer 方法来工作。但是,我想使用 URL 参数并了解为什么它们不起作用。

@Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(true).
                favorParameter(false).
                ignoreAcceptHeader(false).
                useJaf(false);
    }

我找到了一个解决方案,使其可以使用 URL 参数,因为这是我的初衷。 我在 WebConfiguration 上添加了 vnd.ms-excel 的新媒体类型,如下所示。

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false).
                        favorParameter(true).
                        parameterName("format").
                        ignoreAcceptHeader(true).
                        useJaf(false).
                defaultContentType(MediaType.APPLICATION_JSON).
                mediaType("xlsx", new MediaType("application","vnd.ms-excel"));
    }

在请求的 Accept header 上,我添加了值 application/vnd.ms-excel

最后,现在通过使用所需格式调用 excel 端点,它可以正确生成 excel 文件。

localhost:8080/students/excel/excel?format=xlsx