如何从我的 servlet 中获取 org.eclipse.jetty.server.Request

How do I get the org.eclipse.jetty.server.Request from within my servlet

考虑这段代码。这是一项正在进行的工作,但目标是 获得可用于创建全双工的 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 因为 classloader 不一样。 srv_req的class 不过是 org.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实例?

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

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

Request baseRequest = Request.getBaseRequest(httpServletRequest);

但这不会让你走得太远。

org.eclipse.jetty.server.HttpChannel and org.eclipse.jetty.io.EndPoint 没有向应用程序公开 NIO 接口或行为。

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

  • 传输编码
  • 分块
  • 内容编码
  • Gzip
  • 多部分编码
  • 等..

而这正是 HTTP/1.1 给 table 带来的,如果你开始使用 HTTP/2 事情会变得更加复杂(物理连接控制许多虚拟流) .

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

您可以升级连接并使用您自己的 Connection object.

从 HTTP 下退出
jettyEndPoint.setConnection(myConnection);
jettyEndPoint.upgrade(myConnection);

不要忘记实施 Connection.UpgradeTo 以从之前的连接中获取挥之不去的(未处理的)字节。

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

好的,回到 HTTP,您还有哪些选择?

不会公开或让您管理 NIO 选择器。

您必须伪造 jruby 的选择器。

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

如果您不想坚持使用 HTTP,请将连接从 HTTP 升级,请务必先在 HTTP 对话中使用适当的 headers(例如:Connection: upgrade).