多个Ajax请求以相同的URL奇怪的行为多个、奇怪、行为、URL

2023-09-10 20:41:25 作者:ωǒ、情有所归ヾ

我在CherryPy的服务器构建一个奇怪的现象,我想一些帮助了解究竟发生了什么,以及为什么。这里是 server.py

I constructed a strange situation in a CherryPy server, and I'd like some help understanding exactly what's happening, and why. Here is server.py:

import cherrypy
import os
import threading

class Root(object):
    def __init__(self):
        self.count = 0;
        self.lock = threading.Lock()

    @cherrypy.expose
    def app(self):
        with self.lock:
            self.count += 1
        return "Call #%d" % (self.count)

if __name__ == '__main__':
    cherrypy.quickstart(Root(), "/", {"/": { "tools.staticdir.on": True,
                                             "tools.staticdir.dir": os.getcwd() } })

这是一个与一些国家由互斥锁保护非常简单的应用程序。这里是 index.html的

This is a very simple application with some state protected by a mutex. Here is index.html:

<!doctype html>
<script src=http://code.jquery.com/jquery-1.8.2.js></script>
<script src=index.js></script>

(这是确定的HTML是这样的稀疏 - 见这次谈话保罗爱尔兰)这里是 index.js

function request() {
    var cb = function (response) {
        console.log(response);
    };

    $.ajax({
        url: "/app",
        success: cb
    });
}

function go_slow(N, delay) {
    if (N > 0) {
        request();
        window.setTimeout(go_slow, delay, N - 1, delay);
    }
}

function go_fast(N) {
    var i;
    for (i = 0; i < N; i++) {
        request();
    }
}

window.onload = function () {
    //go_slow(100, 0);
    go_fast(100);
};

所有这些文件应该在同一目录下。当我启动CherryPy的服务器,然后访问的http://本地主机:8080 / index.html的,控制台显示的那句呼叫#1100次,而CherryPy的日志显示了一种GET请求/应用程序。在Firefox中,我通过#100看到几个连续的控制台消息,显示#1。 Firefox的行为是我所期待的,因为我做了100明确的Ajax请求,以及相关的这些请求函数应该每次都返回不同的结果。

All of these files should go in the same directory. When I start the CherryPy server and then visit http://localhost:8080/index.html, the console shows the phrase "Call #1" 100 times, and the CherryPy log shows one GET request to "/app". In Firefox, I see several consecutive console messages, showing "#1" through "#100". The Firefox behavior is what I expected, because I made 100 explicit ajax requests, and the function associated to these requests is supposed to return a different result each time.

如果代替 go_fast()我称之为 go_slow() - 使用蹦床(我的变种认为这就是所谓的)来强制Ajax请求从单独的函数调用发出的在不同的时间 - 然后我得到了#1通过这两个Chrome和Firefox#100的行为

If instead of go_fast() I call go_slow() - a variant that uses "trampolining" (I think it's called) to force the ajax requests to be emitted from separate function calls at different times - then I get the "#1" through "#100" behavior on both Chrome and Firefox.

最后,如果我修改应用程序()在CherryPy的服务器方法接受一个参数,它再忽略,像这样(注意的论点,即不出现其他地方):

Finally, if I modify the app() method in the CherryPy server to accept an argument which it then ignores, like this (note the i argument that doesn't appear anywhere else):

@cherrypy.expose
def app(self, i):
    with self.lock:
        self.count += 1
    return "Call #%d" % (self.count)

和我安排 go_fast()功能,使Ajax请求/程序/+ I(其中是循环索引),而不是仅仅/应用程序,通过改变请求()和 go_fast()是这样的:

and I arrange for the go_fast() function to make the ajax request to "/app/" + i" (where i is the loop index) instead of just "/app", by changing request() and go_fast() like this:

function request(i) {
    var cb = function (response) {
        console.log(response);
    };

    $.ajax({
        url: "/app/" + i,
        success: cb
    });
}

function go_fast(N) {
    var i;
    for (i = 0; i < N; i++) {
        request(i);
    }
}

然后我又得到了#1到#100的行为。相反,如果我修改该功能的使用,例如,/程序/ 7作为URL(即替换/程序/+ I 在上面的代码段与/程序/ 7),我得到的呼叫#1100重复在最初的例子。

then I again get the "#1" through "#100" behavior. If instead I modify the function to use, e.g., "/app/7" as the URL (i.e., replace "/app/" + i in the snippet above with "/app/7"), I get 100 repetitions of "Call #1" as in the initial example.

要我来说,它看起来很像的的东西的是缓存的实际上是在最初的情况下取得了(这里我只看到了独一无二的Ajax请求的结果呼叫#1100次)。在Chrome的控制台中的网络选项卡只显示一个Ajax请求接收的200 OK和状态code,据我所知,你必须明确地启用的CherryPy服务器端缓存。也有好奇心火狐给出在这种情况下的预期行为

To me it looks a lot like something is "caching" the result of the one and only ajax request that was actually made in the initial case (where I only saw "Call #1" 100 times). The "Network" tab in Chrome's console just shows the one ajax request receiving a status code of "200 OK" and as far as I know, you have to explicitly enable server-side caching in CherryPy. There is also the curiosity that Firefox gives the expected behavior in this case.

在其他情况下,由于某种原因,这个缓冲机制被击败。蹦床可能会导致浏览器折腾了Ajax请求的直接背景下,$ P $的记忆,一个请求相同的URL被做previously,而contriving需要一个位置参数的URL pventing它只是给每个请求唯一的URL,迫使实际请求出去,而不是使用任何缓存机制。

In the other cases, for one reason or another, this "caching" mechanism is defeated. Trampolining might cause the browser to toss out the immediate context of the ajax request, preventing it from "remembering" that a request to the same URL was made previously, while contriving the URL to require a positional argument simply gives each request a unique URL, forcing an actual request to go out, rather than using any caching mechanism.

谁能解释具体什么是怎么回事?这是一个简单的关于关于Chrome浏览器如何处理很多Ajax请求,在很短的时间内特点?或者是这种情况致命的问题,有状态的AJAX资源?

Can anyone explain concretely what's going on here? Is this simply a peculiarity about about how Chrome handles many ajax requests in a short time frame? Or is this situation a fatal problem with having stateful ajax resources?

推荐答案

我认为这是一个竞争条件与缓存组合:在客户端上假选项请记住,你的对象中的一个线程池是共享的。

I think that this is a race condition in combination with the cache: false option on the client side, remember that your object Root is shared inside a thread pool.

在时间 A 修改 self.count 以及时间 A 另一个X请求(线程)正在返回你他们是在一次新修改的参数 A - 1 块,并没有返回新的计就这一具体要求。

On time A you modify self.count and on time A another X requests (threads) are returning you newly modified parameter they were on time A - 1 on the with block and didn't return that new count on this particular request.

当被修改和失控的with语句的另一个要求是已经在回报等什么决定返回的数字的重复或缺失的吞吐量CherryPy的线程池处理。

When the request that is modifying and getting out of the with statement another is already on the return so what determines the repetition or absence of the numbers returned is the processing throughput of cherrypy's thread pool.