使用Python读取流式http响应"请求"图书馆

时间:2015-01-25 16:57:48

标签: python stream python-requests kubernetes

我正在尝试使用Kubernetes提供的事件流 api使用requests模块。我遇到了一个看起来像的东西 缓冲问题:requests模块似乎滞后一个事件。

我的代码看起来像这样:

r = requests.get('http://localhost:8080/api/v1beta1/watch/services',
                 stream=True)

for line in r.iter_lines():
    print 'LINE:', line

当Kubernetes发出事件通知时,此代码将仅显示 当一个新事件进入时发出的最后一个事件 对于需要响应服务的代码几乎完全没用 添加/删除事件。

我通过在子进程中生成curl而不是使用来解决这个问题 requests库:

p = subprocess.Popen(['curl', '-sfN',
                      'http://localhost:8080/api/watch/services'],
                     stdout=subprocess.PIPE,
                     bufsize=1)

for line in iter(p.stdout.readline, b''):
    print 'LINE:', line

这有效,但代价是一些灵活性。有办法吗? 避免requests库的缓冲问题?

1 个答案:

答案 0 :(得分:6)

此行为是由于iter_lines的错误实施 requests库中的方法。

iter_lines遍历chunk_size块中的响应内容 使用iter_content迭代器的数据。如果少于 可用于从远程读取的chunk_size字节数据 服务器(通常是在读取最后一行时的情况) 输出),读操作将阻塞直到chunk_size个字节 数据可用。

我编写了自己的iter_lines例程,该例程运行正常:

import os


def iter_lines(fd, chunk_size=1024):
    '''Iterates over the content of a file-like object line-by-line.'''

    pending = None

    while True:
        chunk = os.read(fd.fileno(), chunk_size)
        if not chunk:
            break

        if pending is not None:
            chunk = pending + chunk
            pending = None

        lines = chunk.splitlines()

        if lines and lines[-1]:
            pending = lines.pop()

        for line in lines:
            yield line

    if pending:
        yield(pending)

这是有效的,因为os.read将返回少于chunk_size个字节 数据而不是等待填充缓冲区。