Helidon WebServer文件下载:前端获取文件正常但ServerResponse.send抛服务端错误
异常原因
- 当前你将Jersey集成到Helidon WebServer中,请求会先被Jersey的处理链路接管
- 在Jersey的Controller方法中手动调用Helidon原生的
ServerResponse.send(filepath)后,该方法会直接将响应头、响应体全部发送给客户端,并且标记响应为已完成状态 - Jersey本身的处理流程在Controller方法执行结束后,还会尝试自动写入响应状态码、响应头,此时发现响应已经被发送完成,就会抛出
AlreadyCompletedException异常 - 前端能正常下载文件是因为
send方法已经成功把文件内容传输给客户端,后续Jersey链路抛出的异常不影响已经完成的响应传输
解决方案
两种方案任选其一即可:
方案1:遵循Jersey规范编写下载逻辑,不手动调用原生ServerResponse
不需要修改路由配置,仅调整FileController的代码,直接返回Jersey标准的Response对象即可:
@RequestScoped public class FileController { @GET @Path("/{fname}") public Response download(@PathParam("fname") String fname) { java.nio.file.Path filepath = Paths.get("c:/"+fname+".txt"); return Response.ok(filepath) .type(io.helidon.common.http.MediaType.APPLICATION_OCTET_STREAM) .header(Http.Header.CONTENT_DISPOSITION, ContentDisposition.builder() .filename(filepath.getFileName().toString()) .build() .toString()) .build(); } }
方案2:使用Helidon原生路由处理下载请求,不通过Jersey
修改路由配置,直接注册原生的请求处理器,记得删除原有Controller中的download方法避免路径冲突:
private static Routing getRouting() throws Exception{ return Routing.builder() // 原生路由处理文件下载 .get("/filetest/{fname}", (req, res) -> { String fname = req.path().param("fname"); java.nio.file.Path filepath = Paths.get("c:/"+fname+".txt"); res.headers().contentType(io.helidon.common.http.MediaType.APPLICATION_OCTET_STREAM); res.headers().put(Http.Header.CONTENT_DISPOSITION, ContentDisposition.builder() .filename(filepath.getFileName().toString()) .build() .toString()); res.send(filepath); }) // 其他Jersey接口保持原有配置不变 .register("/filetest", JerseySupport.builder().register(FileController.class).build()) .build(); }
内容的提问来源于stack exchange,提问作者MRS
相关产品推荐
相关产品推荐

