首页 > 解决方案 > 如何从我的 servlet 中获取 org.eclipse.jetty.server.Request

问题描述

考虑这段代码。这是一项正在进行中的工作,但目标是获得一个 NIO 通道,我可以使用它来创建一个全双工 RubyIO 实例 (org.jruby.RubyIO),它可以由 NIO 选择器选择。

但首先我想要一个 NIO 通道......

        //  This call returns a `javax.servlet.ServletRequest` but the underlying
        // instance was created by Jetty - it seems to me - and is actually an
        // `org.eclipse.jetty.server.Request`
        ServletRequest srv_req = this.http_servlet_request_wrapper.getRequest();
        Request req;
        ClassLoader cl1 = Request.class.getClassLoader();
        ClassLoader cl2 = srv_req.getClass().getClassLoader();

        System.out.println("DBG: cl1: " + cl1.toString());
        // => DBG: cl1: WebAppClassLoader{66233253}@3f2a3a5

        System.out.println("DBG: cl2: " + cl2.toString());
        // => DBG: cl2: java.net.URLClassLoader@63947c6b

        if (srv_req instanceof Request) {
            System.out.println("DBG: srv_req IS REQUEST");
            req = (Request)srv_req;
            System.out.println("DBG: req class: " + req.getClass().getName());
        } else {
            System.out.println("DBG: srv_req IS NOT REQUEST");
            System.out.println("DBG: srv_req class: " + srv_req.getClass().getName());
            throw new Exception("<expletive deleted>!");
        }

        HttpChannel http_channel = req.getHttpChannel();
        EndPoint end_point = http_channel.getEndPoint();

控制台输出什么...

DBG: cl1: WebAppClassLoader{66233253}@3f2a3a5
DBG: cl2: java.net.URLClassLoader@63947c6b
DBG: srv_req IS NOT REQUEST
DBG: srv_req class: org.eclipse.jetty.server.Request

最后抛出异常。

所以似乎这instanceof不是srv_req一个实例, Reuest因为类加载器不一样。不过, 的类srv_reqorg.eclipse.jetty.server.Request。但是在 servlet 中,我不能这样对待它,也不能强制转换它。

我已阅读https://www.eclipse.org/jetty/documentation/current/jetty-classloading.html 但我仍然不清楚如何srv_req作为 org.eclipse.jetty.server.Request实例访问。

我怀疑我不应该能够从 servlet 执行此操作,但问一下也无妨。

我可以访问javax.servlet.ServletRequest从我的 HttpServletRequestWrapper对象返回的 , 它看起来是一个 org.eclispe.jetty.server.Request实例吗?

或者,我可以从我可以在 servlet 中访问的内容创建一个全双工 NIO 通道吗?

标签: javajettyembedded-jetty

解决方案


首先,org.eclipse.jetty.server.Request要从javax.servlet.HttpServletRequest使用...

Request baseRequest = Request.getBaseRequest(httpServletRequest);

但这不会让你走得很远。

org.eclipse.jetty.server.HttpChannel并且org.eclipse.jetty.io.EndPoint不会将 NIO 接口或行为暴露给应用程序。

它们是通过单个接口实现 HTTP 规范行为的内部类,用于处理...

  • 传输编码
  • 分块
  • 内容编码
  • 压缩包
  • 多部分编码
  • ETC ..

这正是 HTTP/1.1 带来的结果,如果您开始使用 HTTP/2,事情会变得更加复杂(通过物理连接控制许多虚拟流)。

但是,如果您不想使用或不关心 HTTP 怎么办?

Connection您可以使用自己的对象升级连接并从 HTTP 下退出。

jettyEndPoint.setConnection(myConnection);
jettyEndPoint.upgrade(myConnection);

不要忘记实现Connection.UpgradeTo从先前连接中获取延迟(未处理)字节。

但这仍然不能让您获得 NIO,因为EndPointJetty 并没有放弃它,它仍然在进行选择器管理和低级协议行为。(例如来自 HTTP/2 的流)

好的,回到 HTTP,你还有什么选择?

没有任何东西可以暴露或让您管理 NIO 选择器。

您将不得不伪造 jruby 的选择器。

如果您想坚持使用 HTTP,则使用 servlet 规范 Async I/O 行为作为您的 Jetty 端 API 层。

如果您不想坚持使用 HTTP,则将连接从 HTTP 升级,只需确保您在 HTTP 对话中首先使用适当的标头(例如:)这样说Connection: upgrade


推荐阅读