Spring Boot整合Jersey REST API返回Zip文件无法获取文件名问题
问题分析与解决方案
核心问题在于:你先向响应输出流写入了文件内容,之后才设置响应头。HTTP协议要求响应头必须在响应体之前发送,一旦开始写入响应体(文件流),服务器容器会自动发送已设置的响应头,后续修改的Content-Disposition等头信息根本不会生效。
修正后的代码
@Context lateinit var httpServletResponse: HttpServletResponse @POST @Path("/getRecord") @Produces("application/zip", MediaType.APPLICATION_JSON) fun getRecord(@RequestBody recordIdentification: RecordIdentificationRequest) { val compositeRecord: CompositeRecord = service.getRecordFromRequest(recordIdentification) val tmpFile: File? = service.getRecordZip(compositeRecord) tmpFile?.let { file -> // 1. 优先设置所有响应头和状态码 httpServletResponse.status = HttpStatus.OK.value() httpServletResponse.contentType = "application/zip" httpServletResponse.setHeader(HttpHeaders.CONTENT_LENGTH, file.length().toString()) // 指定UTF-8编码避免中文/特殊字符文件名乱码 val contentDisposition = ContentDisposition.attachment() .filename(file.name, StandardCharsets.UTF_8) .build() httpServletResponse.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString()) // 2. 写入文件流,用use函数自动关闭输入流防止资源泄漏 Files.newInputStream(file.toPath()).use { inputStream -> inputStream.transferTo(httpServletResponse.outputStream) } // 3. 完成流操作后刷新并关闭输出流 httpServletResponse.outputStream.flush() httpServletResponse.outputStream.close() } ?: run { // 处理文件不存在的异常场景 httpServletResponse.status = HttpStatus.NOT_FOUND.value() httpServletResponse.contentType = MediaType.APPLICATION_JSON_VALUE httpServletResponse.writer.write("{\"error\": \"Record zip file not found\"}") } }
关键优化点
- 调整执行顺序:必须先设置响应头,再写入响应体,符合HTTP协议规范
- 文件名编码处理:给
filename指定UTF-8编码,避免客户端显示乱码 - 资源自动管理:用Kotlin的
use函数自动关闭输入流,避免资源泄漏 - 异常场景处理:增加文件不存在时的错误响应,提升接口健壮性
内容的提问来源于stack exchange,提问作者abdel
相关产品推荐
相关产品推荐

