[英]How to read Jetty HttpInput (ServletInputStream) many times?
目前我正在使用RestEasy
和Jetty
开发 REST API 。 我对这个 REST API 的计划之一是使用 JAX-RS ContainerRequestFilter
创建一个挂钩插件来处理传入请求所需的任何事情。 Jetty
中ContainerRequestPlugin
的问题是,一旦我调用requestContext.getEntityStream();
在过滤器中,即使我再次设置了实体 Stream,我的端点 Class 也无法再次读取请求。
以下是我的过滤器代码
@Provider
@Priority(2000)
public class DummyRequestFilter implements ContainerRequestFilter{
static Logger log = Logger.getLogger(DummyRequestFilter .class.getName());
@Context
private HttpServletRequest servletRequest;
@Override
public void filter(ContainerRequestContext requestContext) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String requestBody = "";
try {
IOUtils.copy(requestContext.getEntityStream(), baos);
InputStream is1 = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
requestBody = IOUtils.toString(is1);
log.info(requestBody);
requestContext.setEntityStream(is2);
}catch (Exception e) {
log.log(Level.SEVERE,"Exception Occurred",e);
}
}
}
然后这是我的端点 class
@Path("/")
public class DummyService {
Logger log = Logger.getLogger(DummyService .class.getName());
@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Response test(@FormParam("name") String name) {
log.info("Name = "+name);
return Response.status(200).build();
}
}
每当我调用此测试方法时,我都可以看到在过滤器 class 但在端点 class 中发送的名称是NULL
。
后来我发现从 requestContext 返回的 getEntityStream 是 Jetty 自定义ServletInputStream
,即org.eclipse.jetty.server.HttpInput
。 我相信无法在 EndPoint 中读取请求,因为我使用 ByteArrayInputStream 设置了实体 Stream。
所以我的问题是,有没有办法使用通用 InputStream 实现来构建/转换 Jetty HttpInput? 或者有没有其他方法可以解决这种情况? 我可以在哪里多次阅读 Jetty HttpInput?
感谢和问候
毫无疑问,您已经注意到,Servlet 规范不允许您两次读取请求正文内容。
这是一个有意的决定,因为任何此类功能都需要缓存或缓冲响应正文内容。 这导致:
JAX-RS 端点通常要求javax.servlet.http.HttpServletRequest
输入 stream 由于任何原因 (*) 根本没有被读取。
您的代码没有尝试限制您分配的字节 arrays 的大小,使用Zip Bomb很容易滥用您的服务。 (示例:发送 42 KB 的数据,解压为 3.99 PB)
您可能会找到一种特定于 JAX-RS 实现的方式,例如使用 Jersey 内部代码来设置实体 stream,但这种代码将很脆弱,并且可能导致需要修复您的代码并通过更新 Z3CDA26E0C8AEDBF6662ADB42 重新编译。
如果您 go 自定义路由,请特别注意不要在您的代码中引入明显的漏洞,限制您的请求大小,限制您可以缓冲的内容等。
通常,需要修改请求输入 stream 内容的 web 应用程序通过代理 servlets 执行此操作,该代理在逐个缓冲区的基础上实时执行请求的中间人修改。 Jetty 有这样一个 class,方便地称为AsyncMiddleManServlet
。 这实质上意味着您的客户端与与您的端点对话的代理对话,该代理尊重网络行为和网络背压需求。 (缓冲过滤器无法正确处理的东西)
(*) 您可能会通过使用请求中要求请求参数或请求部分的内容意外读取 HttpServletRequest 正文(这需要为某些特定的 Content-Types 读取正文内容)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.