gpt4 book ai didi

java - 如何多次读取Jetty HttpInput(ServletInputStream)?

转载 作者:行者123 更新时间:2023-12-05 06:13:14 28 4
gpt4 key购买 nike

目前我正在使用 RestEasyJetty 开发 REST API。我对这个 REST API 的计划之一是创建一个 Hook 插件,以使用 JAX-RS ContainerRequestFilter 对传入请求执行任何需要的操作。 Jetty 中的 ContainerRequestPlugin 的问题在于,一旦我在 Filter 中调用了 requestContext.getEntityStream();,那么请求将无法即使我再次设置了实体流,也可以通过我的端点类再次读取。

以下是我的过滤器代码

@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);
}
}
}

然后这是我的端点类

@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();
}
}

每当我调用此测试方法时,我都可以看到在 Filter 类中发送的名称,但在 Endpoint 类中名称为 NULL

后来我发现requestContext返回的getEntityStream是Jetty自定义的ServletInputStream,也就是org.eclipse.jetty.server.HttpInput。我相信在 EndPoint 中无法读取请求,因为我使用 ByteArrayInputStream 设置了实体流。

所以我的问题是,有没有什么方法可以使用通用的 InputStream 实现来构建/转换 Jetty HttpInput?还是有其他方法可以解决这种情况?我在哪里可以多次读取 Jetty HttpInput?

感谢和问候

最佳答案

您肯定已经注意到,Servlet 规范不允许您读取请求正文内容两次。

这是一个有意的决定,因为任何此类功能都需要缓存或缓冲响应正文内容。这导致:

  • 针对您的网络应用程序的各种 DoS/拒绝服务攻击。
  • 当您的代码第二次从缓冲区读取请求并且没有产生网络流量来重置空闲超时时,请求处理空闲超时。
  • 无法受益于或使用 Servlet 异步 I/O 处理。

JAX-RS 端点通常要求 javax.servlet.http.HttpServletRequest 输入流因任何原因根本未被读取 (*)。

您的代码没有尝试限制您分配的字节数组的大小,使用 Zip Bomb 很容易滥用您的服务. (示例:发送 42 KB 的数据,解压缩后为 3.99 PB)

您可能会发现一种特定于 JAX-RS 实现的方式,例如使用 Jersey 内部代码来设置实体流,但这种代码很脆弱,可能需要修复您的代码并重新编译以更新您的代码泽西图书馆。

如果您采用自定义路线,请格外小心,不要在您的代码中引入明显的漏洞,限制您的请求大小,限制您可以缓冲的内容等。

通常,需要修改请求输入流内容的 web 应用程序通过代理 servlet 来完成,代理 servlet 在逐个缓冲区的基础上实时执行请求的中间人修改。 Jetty 有这样一个类,方便地称为 AsyncMiddleManServlet。这实质上意味着您的客户端与代理对话,代理与您的端点对话,后者尊重网络行为和网络背压需求。 (缓冲过滤器无法正确处理的事情)

(*) 您可能会意外地读取 HttpServletRequest 主体,方法是使用请求中要求请求参数或请求部分的东西(这需要为某些特定的内容类型读取主体内容)

关于java - 如何多次读取Jetty HttpInput(ServletInputStream)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63377863/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com