繁体   English   中英

支持分块编码的 Python HTTP 服务器?

[英]Python HTTP server that supports chunked encoding?

我正在寻找一个支持分块编码回复的支持良好的多线程 Python HTTP 服务器。 (即响应中的“传输编码:分块”)。 为此目的,最好的 HTTP 服务器基础是什么?

Twisted 支持分块传输编码(API 链接) (另请参阅HTTPChannel的 API 文档)。 有许多使用 Twisted 的生产级项目(例如,Apple 将它用于 Mac OS X Server 中的 iCalendar 服务器),因此它得到了很好的支持并且非常健壮。

Twisted 支持分块传输,并且这样做是透明的。 即,如果您的请求处理程序没有指定响应长度,twisted 将自动切换到分块传输,并且每次调用 Request.write 都会生成一个块。

您可以使用 Python 的 HTTPServer 实现一个简单的分块服务器,方法是将其添加到您的服务函数中:

    def _serve(self, res):
        response = next(res)

        content_type = 'application/json'

        self.send_response(200)
        self.send_header('Content-Type', content_type)
        self.send_header('Transfer-Encoding', 'chunked')
        self.end_headers()

        try:
            while True:
                r = response.encode('utf-8')
                l = len(r)
                self.wfile.write('{:X}\r\n{}\r\n'.format(l, r).encode('utf-8'))

                response = next(it)
        except StopIteration:
            pass

        self.wfile.write('0\r\n\r\n'.encode('utf-8'))

我不建议将其用于生产用途。

我设法使用Tornado做到了:

#!/usr/bin/env python

import logging

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options

define("port", default=8080, help="run on the given port", type=int)

@tornado.web.stream_request_body
class MainHandler(tornado.web.RequestHandler):
    def post(self):
        print()
    def data_received(self, chunk):
        self.write(chunk)

        logging.info(chunk)

def main():
    tornado.options.parse_command_line()

    application = tornado.web.Application([
        (r"/", MainHandler),
    ])

    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)

    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()

下面的脚本是一个完整的工作示例。 它可以用作 CGI 脚本在 Apache 或 IIS 下流式传输数据:

#!/usr/bin/env pythonw
import sys
import os
import time

# Minimal length of response to avoid its buffering by IIS+FastCGI
# This value was found by testing this script from a browser and
# ensuring that every event received separately and in full
response_padding = 284


def send_chunk(r):
    # Binary write into stdout
    os.write(1, "{:X}\r\n{}\r\n".format(len(r), r).encode('utf-8'))


class Unbuffered(object):
    """
    Stream wrapper to disable output buffering
    To be used in the CGI scripts
    https://stackoverflow.com/a/107717/9921853
    """
    def __init__(self, stream):
        self.stream = stream

    def write(self, data):
        self.stream.write(data)
        self.stream.flush()

    def writelines(self, lines):
        self.stream.writelines(lines)
        self.stream.flush()

    def __getattr__(self, attr):
        return getattr(self.stream, attr)


# Ensure stdout is unbuffered to avoid problems serving this CGI script on IIS
# Also web.config should have responseBufferLimit="0" applied to the CgiModule handler
sys.stdout = Unbuffered(sys.stdout)
print(
    "Transfer-Encoding: chunked\n"
    "Content-Type: text/event-stream; charset=utf-8\n"
)

# Fixing an issue, that IIS provides a wrong file descriptor for stdin, if no data passed to the POST request
sys.stdin = sys.stdin or open(os.devnull, 'r')

progress = 0

send_chunk(
    (
        "event: started\n"
        f"data: {progress}"
    ).ljust(response_padding) + "\n\n"
)

while progress < 5:
    time.sleep(2)
    progress += 1

    send_chunk(
        (
            "event: progress\n"
            f"data: {progress}"
        ).ljust(response_padding) + "\n\n"
    )

time.sleep(2)

send_chunk(
    (
        "event: completed\n"
        f"data: {progress+1}"
    ).ljust(response_padding) + "\n\n"
)

# To close stream
send_chunk('')

########################################################
# All Done

我很确定符合 WSGI 的服务器应该支持这一点。 本质上,WSGI 应用程序返回可迭代的块,网络服务器返回这些块。 我没有这方面的第一手经验,但这里有一个兼容服务器列表

我应该认为,如果 WSGI 服务器不符合您的要求,使用 Python 的内置CGIHTTPServer来滚动您自己的服务器会相当容易。 它已经是多线程的,因此您可以将响应分块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM