Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 金字塔流响应体_Python_Ajax_Pyramid_Server Sent Events - Fatal编程技术网

Python 金字塔流响应体

Python 金字塔流响应体,python,ajax,pyramid,server-sent-events,Python,Ajax,Pyramid,Server Sent Events,我试图从我的金字塔应用程序流式传输服务器发送的事件,但我不知道如何从我的视图流式传输响应主体。下面是我正在使用的测试视图(它完全没有实现SSE,只是为了解决流部分): 这将产生ValueError:无法将视图可调用函数pdiff.views.iter_test的返回值转换为响应对象。返回的值为。 我尝试了返回响应(app_iter=test_iter()),这至少不会出错,但不会流式处理响应-它会等到生成器完成后再将响应返回到我的浏览器 我知道这可以简单地为每个请求返回一个事件,并允许客户端在每

我试图从我的金字塔应用程序流式传输服务器发送的事件,但我不知道如何从我的视图流式传输响应主体。下面是我正在使用的测试视图(它完全没有实现SSE,只是为了解决流部分):

这将产生
ValueError:无法将视图可调用函数pdiff.views.iter_test的返回值转换为响应对象。返回的值为。

我尝试了
返回响应(app_iter=test_iter())
,这至少不会出错,但不会流式处理响应-它会等到生成器完成后再将响应返回到我的浏览器


我知道这可以简单地为每个请求返回一个事件,并允许客户端在每个事件后重新连接,但我更愿意通过从单个请求流式传输多个事件来保持服务器发送事件的实时性,而不需要重新连接延迟。如何使用Pyramid执行此操作?

如果未为视图指定任何渲染器,则必须返回响应对象。金字塔响应对象有一个用于返回迭代器的特殊参数。所以你应该这样做:

import time
from pyramid.response import Response


@view_config(route_name='iter_test')
def iter_test(request):

    def test_iter():
        for _ in range(5):
            yield str(time.time())
            print time.time()
            time.sleep(1)

    return Response(app_iter=test_iter())
我还对代码进行了一些编辑,以使其更具可读性

更新

我尝试了返回响应(app_iter=test_iter()),它至少不会出错,但不会流式传输响应—它会等到生成器完成后,再将响应返回到我的浏览器


我想问题在于缓冲。尝试发送一个非常大的迭代器。

我刚才做了一些测试,以尝试事件源/服务器发送的事件。我刚刚测试过,它在金字塔1.5a上仍然可以正常工作

@view_config(route_name = 'events')
def events(request):
    headers = [('Content-Type', 'text/event-stream'),
               ('Cache-Control', 'no-cache')]
    response = Response(headerlist=headers)
    response.app_iter = message_generator()
    return response

def message_generator():
    socket2 = context.socket(zmq.SUB)
    socket2.connect(SOCK)
    socket2.setsockopt(zmq.SUBSCRIBE, '')
    while True:
        msg = socket2.recv()
        yield "data: %s\n\n" % json.dumps({'message': msg})
这里的完整示例:。看一看


我不太清楚为什么我的有效而你的无效。也许是头球。或者在每条消息之后添加两个
'\n'
。顺便说一句,如果您正确地查看了事件源规范,则必须使用
数据:
作为每个新事件的前缀,并使用
\n\n
作为事件分隔符。

我发现了问题。原来我的应用程序代码很好,问题出在女服务员和nginx身上:

  • Waitress是默认的web服务器金字塔使用的,它以18000字节块缓冲所有输出(有关详细信息,请参阅)

  • nginx对我隐藏了问题的根源,nginx是我放在金字塔应用程序前面的web服务器,它还缓冲响应

  • (1) 可通过以下任一方法解决:

    • 在.ini文件中配置waiteress的
      send_bytes=1
      。这解决了流媒体的问题,但使你的整个应用程序超慢。正如@Zitrax所提到的,您可以使用更高的值恢复一些速度,但是任何高于1的值都有可能使消息卡在缓冲区中

    • 切换到gunicorn。我不知道gunicorn是否只是使用了更小的缓冲区,或者它在
      app\u iter
      中是否表现得更好,但它工作了,并保持了我的应用程序的速度

    (2) 可以通过将nginx配置为禁用流路由的缓冲来解决此问题

    您需要在nginx配置中设置
    proxy\u buffering off
    。此设置适用于通过
    proxy\u pass
    托管的站点。如果您没有使用
    proxy\u pass
    您可能需要不同的设置

    • 您可以将nginx配置为基于请求头为每个响应动态启用/禁用缓冲,如所示(EventSource/Server发送事件的良好解决方案)

    • 您也可以在nginx conf中的
      位置
      块中对此进行配置。如果您使用的是EventSource以外的内容,并且您不希望收到特定的头,或者如果您使用的是EventSource,但希望从普通浏览器选项卡调试响应,则这是很好的,无法发送请求中的
      Accept
      标题


    在我的测试中,
    应用程序未流式传输到浏览器。相反,webob在返回结果之前运行迭代器直到完成(相关的webob代码如下:)。要使EventSource streams正常工作,我的迭代器需要是无限的(即,不容易运行到完成),结果需要在生成时传递到浏览器,而不是一大块。@spiffytech您链接的代码是“body”getter,它真正将“app_iter”压缩为单个字符串。但WebOb并没有做到这一点:请参阅方法代码。我没有检查金字塔的来源,但我想它也没有这样做。因此,如果您返回一个带有“app_iter”的响应对象,并且不访问代码中的“body”,WebOb将返回“app_iter”。缓冲看起来并不是问题所在-我尝试了一个更大的生成器(50k项),而Pyramid仍然等到它完成后才发送结果。无论如何,我不需要等待-服务器设置事件流的要点是事件立即到达浏览器,所以我不能等待缓冲区填满。另外,我链接到的webob代码部分实际上被调用了-我通过在迭代器中设置断点并在迭代器运行时查看调用堆栈得到了行号,使用上面的代码-无法访问正文和相应的响应对象。谢谢!我知道我的方法肯定会奏效,这让我想到了其他潜在的问题,这些问题导致我找到了解决方案。这已经不起作用了。它不能返回字节,因此请使用
    yield”数据:%s\n\n“%json.dumps({'message':msg}).encode()
    我遇到了同样的问题,并且确实将send_字节设置为1起到了作用。然而,它让一切都变得非常缓慢(我在不到0.5秒的时间内加载了页面,之后的加载时间超过了10秒)。我目前无法切换到gunicorn,因为它只是Unix。一种折衷方法是将send_字节设置为大于1且小于18000的值。在我的情况下,100个相当不错。
    @view_config(route_name = 'events')
    def events(request):
        headers = [('Content-Type', 'text/event-stream'),
                   ('Cache-Control', 'no-cache')]
        response = Response(headerlist=headers)
        response.app_iter = message_generator()
        return response
    
    def message_generator():
        socket2 = context.socket(zmq.SUB)
        socket2.connect(SOCK)
        socket2.setsockopt(zmq.SUBSCRIBE, '')
        while True:
            msg = socket2.recv()
            yield "data: %s\n\n" % json.dumps({'message': msg})