[英]How to read Jetty HttpInput (ServletInputStream) many times?
Currently im developing a REST API using RestEasy
and Jetty
.目前我正在使用
RestEasy
和Jetty
开发 REST API 。 One of my plan with this REST API is to create a hook plugin to do anything needed with the incoming request utilizing JAX-RS ContainerRequestFilter
.我对这个 REST API 的计划之一是使用 JAX-RS
ContainerRequestFilter
创建一个挂钩插件来处理传入请求所需的任何事情。 The thing with ContainerRequestPlugin
in Jetty
here is that once I called requestContext.getEntityStream();
Jetty
中ContainerRequestPlugin
的问题是,一旦我调用requestContext.getEntityStream();
in the Filter then the request wont be able to be read again by my EndPoint Class even if I have set the Entity Stream again.在过滤器中,即使我再次设置了实体 Stream,我的端点 Class 也无法再次读取请求。
Following are my Filter code以下是我的过滤器代码
@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);
}
}
}
Then here is my endpoint class然后这是我的端点 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();
}
}
Whenever I called this test method I can see the name sent in Filter class but in the Endpoint class name is NULL
.每当我调用此测试方法时,我都可以看到在过滤器 class 但在端点 class 中发送的名称是
NULL
。
Later then I figured out that the getEntityStream returned from requestContext is Jetty custom ServletInputStream
that is org.eclipse.jetty.server.HttpInput
.后来我发现从 requestContext 返回的 getEntityStream 是 Jetty 自定义
ServletInputStream
,即org.eclipse.jetty.server.HttpInput
。 I believe the request cannot be read in EndPoint since I set the Entity Stream using ByteArrayInputStream.我相信无法在 EndPoint 中读取请求,因为我使用 ByteArrayInputStream 设置了实体 Stream。
So my question will be, is there any way to build/convert Jetty HttpInput using generic InputStream implementation?所以我的问题是,有没有办法使用通用 InputStream 实现来构建/转换 Jetty HttpInput? or is there any other way to work around this case?
或者有没有其他方法可以解决这种情况? where I can read Jetty HttpInput many times?
我可以在哪里多次阅读 Jetty HttpInput?
Thanks & Regards感谢和问候
As you have no doubt noticed, the Servlet spec does not allow you to read the Request body contents twice.毫无疑问,您已经注意到,Servlet 规范不允许您两次读取请求正文内容。
This is an intentional decision as any such feature would require caching or buffering the response body content.这是一个有意的决定,因为任何此类功能都需要缓存或缓冲响应正文内容。 Which leads to:
这导致:
JAX-RS endpoints typically require that the javax.servlet.http.HttpServletRequest
input stream has not been read, at all, for any reason (*). JAX-RS 端点通常要求
javax.servlet.http.HttpServletRequest
输入 stream 由于任何原因 (*) 根本没有被读取。
Your code makes no attempt to limit the size of the byte arrays you allocate, it would be easy to abuse your service with a Zip Bomb .您的代码没有尝试限制您分配的字节 arrays 的大小,使用Zip Bomb很容易滥用您的服务。 (example: sending 42 kilobytes of data that unpacks to 3.99 petabytes)
(示例:发送 42 KB 的数据,解压为 3.99 PB)
You may find a JAX-RS implementation specific way, such as using Jersey internal code to set the entity stream, but that kind of code will be fragile and likely result in the need to fix your code and recompile with updates to your Jersey library.您可能会找到一种特定于 JAX-RS 实现的方式,例如使用 Jersey 内部代码来设置实体 stream,但这种代码将很脆弱,并且可能导致需要修复您的代码并通过更新 Z3CDA26E0C8AEDBF6662ADB42 重新编译。
If you go the custom route, please be take extra care to not introduce obvious vulnerabilities in your code, limit your request size, limit what you can buffer, etc.如果您 go 自定义路由,请特别注意不要在您的代码中引入明显的漏洞,限制您的请求大小,限制您可以缓冲的内容等。
Typically webapps that need to modify request input stream content do it via proxy servlets that perform middle-man modification of the request in real-time, on a buffer by buffer basis.通常,需要修改请求输入 stream 内容的 web 应用程序通过代理 servlets 执行此操作,该代理在逐个缓冲区的基础上实时执行请求的中间人修改。 Jetty has such a class, called conveniently
AsyncMiddleManServlet
. Jetty 有这样一个 class,方便地称为
AsyncMiddleManServlet
。 This essentially means your client talks to the proxy which talks to your endpoint, which honors network behaviors and network backpressure needs.这实质上意味着您的客户端与与您的端点对话的代理对话,该代理尊重网络行为和网络背压需求。 (something a buffering filter wouldn't be able to handle properly)
(缓冲过滤器无法正确处理的东西)
(*) You can accidentally read the HttpServletRequest body by using things from the request that ask for the request parameters or the request parts (which require that the body content be read for certain specific Content-Types) (*) 您可能会通过使用请求中要求请求参数或请求部分的内容意外读取 HttpServletRequest 正文(这需要为某些特定的 Content-Types 读取正文内容)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.