【问题标题】:Does Tomcat call the doPost method of a servlet before or after it receives the post body?Tomcat 是在收到 post 正文之前还是之后调用 servlet 的 doPost 方法?
【发布时间】:2019-03-26 22:17:00
【问题描述】:

当 Tomcat 接收到一个路由到 servlet 的 Post 请求时,Tomcat 是等到获取整个 post body 后再调用 servlet 的处理程序方法,还是立即调用该方法?

我通过扩展HttpServlet 类并实现doPost(request, response) 方法创建了一个简单的servlet。在我的方法中,我调用request.getInputStream() 通过输入流检索帖子正文。

假设客户端正在发布一个非常大的对象,并且在上传的中途,客户端中止上传或他们的互联网连接失败。在这种情况下,我的 doPost 方法永远不会被调用吗?还是会被调用,但在读取输入流的过程中失败?

差异对我来说很重要,因为我想知道我是否能够在输入流读取期间捕捉到 IOException 并在那里采取一些行动。

【问题讨论】:

    标签: java tomcat servlets


    【解决方案1】:

    doPost() 方法将在读取正文之前被调用。

    在通常的 POST 请求中,当您调用 request.getParameter(..).getParameterNames().getPart(..).getParts() 时,会读取和使用正文。如果你能打到request.getInputStream()就说明body还没有被读取。

    使用 HTTP/1.1 协议,如果客户端使用 Expect 标头请求它,服务器可能会向客户端 (100 Continue) 发送确认。它发生在阅读正文之前。

    【讨论】:

    • 严格来说这不是真的 - doPost 在整个请求被读取之前肯定会被调用,但不能保证正文的任何​​部分都没有被读取。
    【解决方案2】:

    查看 Tomcat 源代码,我们看到默认的 ServeltInputStream 实现是从 org.apache.catalina.connector.InputBuffer 的实例读取的 CoyoteInputStream。该缓冲区具有各种特定于协议的扩展类。似乎在调用doPost() 之前完全读取的请求正文是一个实现细节,具体取决于所使用的协议,例如对于StreamInputBuffer 类中的 HTTP2,我们看到以下注释:

    需要两个缓冲区来避免各种多线程问题。 这些问题源于 Stream(或 应用程序使用的请求/响应)在一个线程中处理 但连接在另一个处理。因此有可能 可以在应用程序之前收到请求正文帧 准备阅读它。如果没有缓冲,则处理 连接(因此所有流)将阻塞,直到应用程序 读取数据。因此,必须缓冲传入的数据。 如果只使用一个缓冲区,那么它可能会损坏,如果 连接线程正试图同时添加到它 应用程序被阅读。虽然应该可以避免这种情况 通过仔细使用缓冲区损坏它仍然需要 与使用两个缓冲区相同的副本,并且行为会更少 清除。

    这适用于其他 servlet 容器,例如如果连接可以挂在里面,JBoss WildFly 可以在基于[WFLY-6671] ajp connection hangs if a post HTTP request header contains 'Transfer-Encoding: chunked' 完全读取请求正文之前开始执行doPost()

    【讨论】:

    • 感谢您的好评。我通过中止一些大型上传对此进行了测试,发现确实在上传期间调用了我的函数,并且在尝试读取流时收到了 IOException。这是我所希望的。
    猜你喜欢
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 2016-05-18
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多