【问题标题】:Is it possible to receive out-of-order responses with HTTP?是否可以使用 HTTP 接收乱序响应?
【发布时间】:2016-12-02 21:38:09
【问题描述】:

Sec 8.1.2.2 Pipelining 说:

“服务器必须按照与请求相同的顺序发送对请求的响应 已收到”。

所以,我想,如果我从浏览器发出多个 AJAX 请求,它们仍然会按照服务器接收它们的顺序进行处理。

但后来,我从 Alex Maccaw 那里读到了这个 post,他说:

“最后一个问题是并行发送的 Ajax 请求。如果用户创建 一条记录,然后立即更新同一条记录,会发出两个Ajax请求 同时,一个 POST 和一个 PUT。但是,如果服务器处理“更新”请求 在“创造”之前,它会吓坏了。它不知道什么记录需要更新,因为 记录尚未创建。

解决方案是通过管道传输 Ajax 请求,串行传输它们。脊柱 默认情况下执行此操作,将 POST、PUT 和 DELETE Ajax 请求排队,以便发送一个 一次。只有在前一个请求成功返回后才发送下一个请求。”

那么,如何以编程方式创建 Alex Maccaw 提到的场景?

【问题讨论】:

    标签: ajax http web-applications asynchronous


    【解决方案1】:

    我认为简而言之,您的问题的答案是“是”。

    HTTP 1.1 不禁止打开到同一个服务器的多个 TCP 连接(实际上它建议两个),并且所有现代浏览器都这样做(事实上,大多数浏览器会打开六个或更多)。见Max parallel http connections in a browser?。请求-响应周期可以在这些连接中的每一个上进行,并且由于各种原因,某些请求-响应周期可能比其他周期快得多。网络拥塞、请求的复杂性、处理您的请求的特定“工作人员”的速度和负载等。这意味着稍后开始的请求的请求-响应周期可能比开始的请求周期更早完成早一点。

    "服务器必须以与请求相同的顺序发送对请求的响应 已收到”。

    此语句仅适用于管道化多个 http 请求,即通过一个 TCP 连接发送多个请求,而不等待每个请求的响应。它不适用于打开到同一服务器的多个 TCP 连接。

    通常,每个 tcp 连接在同一时间只有一个请求。客户端等待响应,当它得到响应时,可能会重用连接以获取新请求。因此,就常规(非流水线)http 而言,甚至没有“响应顺序”的概念,因为 TCP 连接上只有一个请求-响应周期。

    使用流水线,可以在一个 TCP 连接上触发多个 http 请求。让响应按顺序返回很重要,因为这是响应与原始请求匹配的方式。 (匹配对请求的响应可能会以不同的方式完成,例如通过在每个响应上提供完整请求的哈希值,但那不是重点)。

    另外,很高兴知道(默认)对 HTTP 管道的支持并不广泛。 Chromium 项目不愿意启用它:https://insouciant.org/tech/status-of-http-pipelining-in-chromium/。 Firefox 仍然没有启用它。 https://bugzilla.mozilla.org/show_bug.cgi?id=264354

    另一方面,Apple 已在 IOS5 的 safari 中启用了对它的支持,这可能是因为移动设备上的请求-响应延迟是一个更大的问题。 http://www.guypo.com/mobile/ios5-top10-performance-changes/ Android股票浏览器也是如此。至少是 Chrome 之前的版本。 http://www.guypo.com/mobile/http-pipelining-big-in-mobile/

    Alex Maccaw 在你引用的关于 Spine 的帖子中写道:

    解决方案是通过管道传输 Ajax 请求,串行传输它们。

    我认为管道这个术语在这种情况下有点令人困惑。首先,Spine 所做的“流水线”与 HTTP 中的流水线请求完全不同。其次,我认为我将这个特殊的特性称为 Spine 请求队列。 Spine 将请求排队,并按添加顺序处理队列中的项目。

    一般来说,我认为“流水线”一词最适合用于有意使事情变得更快的情况,而“排队”最适合用于有意使事情变慢(以防止竞争条件或减轻处理器的负载)例如,排队的项目)。

    【讨论】:

    • 你说得对,流水线连接和持久连接是不同的东西。持久连接可能支持也可能不支持流水线。
    • 我现在很困惑选择哪一个作为答案! @Jon 是第一个回复的,他的回复让我明白了,但你付出了很多努力来整理和总结整个事情!
    【解决方案2】:

    它们不会被同步处理,除非 WebServer 只有 1 个线程来处理可能只是有意发生的请求(可能在开发环境下)。大多数情况下,Web 服务器有数百个线程可用于处理传入的请求,并且由于一个请求可能比另一个请求花费更长的时间,因此响应可能会乱序返回。这就是它被称为 A(asynchronous)JAX 的原因。

    1 个请求可能需要整整一秒才能响应,而请求 2 和 3 需要 25ms 才能响应,因此第一个请求响应在第二个和第三个请求之后出现。

    您可以强制同步循环,但代价是一切都停止,直到请求被返回和处理,(即使是 JS 加载微调器也会停止)。

    请参阅这篇关于强制同步 (SJAX) 请求的文章。 http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX

    【讨论】:

    • 那么,你说的是 Sec 8.1.2.2 Pipelining 中这条语句的含义:“服务器必须按照接收请求的顺序发送对请求的响应”?
    • 关于流水线的声明仅适用于流水线多个http请求,即使用一个tcp连接进行多个请求,而不等待每个请求的响应。它不适用于打开到同一服务器的多个 tcp 连接。例如:stackoverflow.com/questions/985431/…
    【解决方案3】:

    RFC 2616 使用术语“流水线”来指代:

    • HTTP 请求和响应可以在连接上进行管道传输。 流水线允许客户端发出多个请求,而无需 等待每个响应,允许单个 TCP 连接 使用效率更高,运行时间更短。

    所以这里的流水线意味着using a persistent HTTP connection 发出多个请求。这是浏览器必须支持的功能,目前几乎所有浏览器都不支持或默认关闭。所以现在,当您发出许多普通的 AJAX 请求时,响应总是有可能乱序返回。

    大多数时候这不是问题。如果是,您可以采取适当的措施来手动“管道”请求;它们仍然通过单独的连接出去,但是您的代码被设计为等到待处理的请求完成后再发出下一个请求。在您链接到的文章中,此功能内置在 Spine 中。

    【讨论】:

    • 那么,AJAX 请求决定是使用不同的连接还是重用现有的连接的依据是什么?从您所说的看来,如果启用了流水线,AJAX 请求将在相同的连接上发送(因此给人一种“更慢”的感觉),而当它被禁用时,每个 AJAX 请求都可以在不同的连接上发送,并且因此收到乱序响应(并因此给人一种“更快”的感觉)!因此,流水线似乎以牺牲应用程序响应性为代价来实现 TCP 连接的有效使用。如果我错了,请纠正我。
    • @vendhan:你没有错。 :-) HTTP流水线主要是一种节省服务器资源的工具,恕我直言,这是最相关的观点。在客户端,当您需要序列化时,您只需通过保留新请求的代码来强制执行它。
    • 太棒了!您能否阐明(如果有)任何其他变量,除了启用/禁用流水线之外,这些变量将确定 AJAX 请求是应该在现有连接上发送还是应该使用新连接?
    • @vendhan:使用现有连接是流水线的定义,因此没有其他变量。这只是描述同一事物的两种方式。
    • Jon 在我发布此消息后不久,我意识到我的评论可能会被视为指出错误,而我的意图只是澄清,因为@vendhan 似乎没有很好地掌握材料一般。深夜评论堆栈溢出的危险。 ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2021-06-02
    • 2020-12-08
    • 2017-10-13
    • 2020-04-17
    • 2016-10-13
    • 1970-01-01
    相关资源
    最近更新 更多