Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.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/8/http/4.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 ZMQ中的HTTP服务器或如何使用pyzmq处理POST请求?_Python_Http_Zeromq_Pyzmq - Fatal编程技术网

Python ZMQ中的HTTP服务器或如何使用pyzmq处理POST请求?

Python ZMQ中的HTTP服务器或如何使用pyzmq处理POST请求?,python,http,zeromq,pyzmq,Python,Http,Zeromq,Pyzmq,我正在尝试使用ZMQ\u流socket创建一个HTTP服务器 当我执行一个简单的POST请求时: POST HTTP/1.1 Host: localhost:5555 Cache-Control: no-cache Postman-Token: 67004be5-56bc-c1a9-847a-7db3195c301d Apples to Oranges! 以下是我如何使用pyzmq处理此问题: context = zmq.Context() socket = context.socket(

我正在尝试使用
ZMQ\u流
socket创建一个HTTP服务器

当我执行一个简单的
POST
请求时:

POST  HTTP/1.1
Host: localhost:5555
Cache-Control: no-cache
Postman-Token: 67004be5-56bc-c1a9-847a-7db3195c301d

Apples to Oranges!
以下是我如何使用pyzmq处理此问题:

context = zmq.Context()
socket = context.socket(zmq.STREAM)
socket.bind("tcp://*:5555")

while True:
    # Get HTTP request
    parts = []
    id_, msg = socket.recv_multipart()  # [id, ''] or [id, http request]
    parts.append(id_)
    parts.append(msg)
    if not msg:
        # This is a new connection - this is just the identify frame (throw away id_)
        # The body will come next
        id_, msg = socket.recv_multipart() # [id, http request]
        parts.append(id_)
        parts.append(msg)

        end = socket.recv_multipart() # [id*, ''] <- some kind of junk? 
        parts.append(end)

    print("%s" % repr(parts))
因此,我明白:

  • “\x00\x80\x00\x00)”,
    是连接的标识。这最初由
    ZMQ\u STREAM
    socket设置。在随后的请求中,它似乎不存在
  • \x00\x80\x00\x00)
    再次是身份,这是我们从
    ZMQ\u流
    socket的客户端后续请求中看到的
  • 然后是实际的HTTP请求
  • 但是最后一对神奇数字:
    ['\x00\x80\x00\x00*','']

    那到底代表什么

    参考资料:

  • HTTP 1.1规范:
  • 但最后一对神奇数字:['\x00\x80\x00\x00*','] 那到底代表什么

    这是一个新连接,具有一个新的连接ID。连接ID是一个整数计数器,您可以使用Python内置代码查看
    ord(''))=41
    ord('*')=42
    ,这是序列中的下一个数字

    使用ZMQ_流编写HTTP服务器时,您必须小心,因为这比在建立连接后仅接收一条消息要复杂得多。 问题主要是你不能保证一个请求会完成;身体可能以块的形式到达,可能包含多条信息。您将不得不读取HTTP头并处理接收分块的正文

    下面是一个处理来自curl的POST请求的示例:

    from traceback import print_exc
    import zmq
    from tornado.httputil import HTTPHeaders
    
    class BadRequest(Exception):
        pass
    
    class ConnectionLost(Exception):
        pass
    
    def parse_request(request):
        """Parse a request verp, path, and headers"""
        first_line, header_lines = request.split(b'\r\n', 1)
        verb, path, proto = first_line.decode('utf8').split()
        headers = HTTPHeaders.parse(header_lines.decode('utf8', 'replace'))
        return verb, path, headers
    
    
    def recv_body(socket, headers, chunks, request_id):
        """Receive the body of a request"""
        if headers.get('expect', '').lower() == '100-continue':
            if 'Content-Length' not in headers:
                # Don't support chunked transfer: http://tools.ietf.org/html/rfc2616#section-3.6.1
                print("Only support specified-length requests")
                socket.send_multipart([
                    request_id, b'HTTP/1.1 400 (Bad Request)\r\n\r\n',
                    request_id, b'',
                ])
                msg = 1
                while msg != b'':
                    # flush until new connection
                    _, msg = socket.recv_multipart()
                raise BadRequest("Only support specified-length requests")
    
            socket.send_multipart([request_id, b'HTTP/1.1 100 (Continue)\r\n\r\n'], zmq.SNDMORE)
    
            content_length = int(headers['Content-Length'])
            print("Waiting to receive %ikB body" )
            while sum(len(chunk) for chunk in chunks) < content_length:
                id_, msg = socket.recv_multipart()
                if msg == b'':
                    raise ConnectionLost("Disconnected")
                if id_ != request_id:
                    raise ConnectionLost("Received data from wrong ID: %s != %s" % (id_, request_id))
                chunks.append(msg)
        return b''.join(chunks)
    
    
    print(zmq.__version__, zmq.zmq_version())
    
    
    socket = zmq.Context().socket(zmq.STREAM)
    socket.bind("tcp://*:5555")
    
    
    while True:
        # Get HTTP request
        request_id, msg = socket.recv_multipart()
        if msg == b'':
            continue
        chunks = []
        try:
            request, first_chunk = msg.split(b'\r\n\r\n', 1)
            if first_chunk:
                chunks.append(first_chunk)
            verb, path, headers = parse_request(request)
            print(verb, path)
            print("Headers:")
            for key, value in headers.items():
                print('  %s: %s' % (key, value))
            body = recv_body(socket, headers, chunks, request_id)
            print("Body: %r" % body)
        except BadRequest as e:
            print("Bad Request: %s" % e)
        except ConnectionLost as e:
            print("Connection Lost: %s" % e)
        except Exception:
            print("Failed to handle request", msg)
            print_exc()
            socket.send_multipart([
                request_id, b'HTTP/1.1 500 (OK)\r\n\r\n',
                request_id, b''])
        else:
            socket.send_multipart([
                request_id, b'HTTP/1.1 200 (OK)\r\n\r\n',
                request_id, b''])
    
    来自回溯导入打印\u exc
    导入zmq
    从tornado.httputil导入HTTPHeaders
    类请求(异常):
    通过
    类ConnectionLost(异常):
    通过
    def解析_请求(请求):
    “”“分析请求的verp、路径和标头”“”
    第一行,标题行=request.split(b'\r\n',1)
    动词,路径,proto=first_line.decode('utf8').split()
    headers=HTTPHeaders.parse(header\u line.decode('utf8','replace'))
    返回动词、路径、标题
    def recv_正文(套接字、头、块、请求id):
    “”“接收请求的正文”“”
    if headers.get('expect','').lower()='100 continue':
    如果“内容长度”不在标题中:
    #不支持分块传输:http://tools.ietf.org/html/rfc2616#section-3.6.1
    打印(“仅支持指定长度的请求”)
    socket.send\u多部分([
    请求id,b'HTTP/1.1 400(错误请求)\r\n\r\n',
    请求\u id,b“”,
    ])
    msg=1
    而味精!=b':
    #冲洗至新连接
    _,msg=socket.recv_multipart()
    raise BADDREQUEST(“仅支持指定长度的请求”)
    socket.send\u multipart([request\u id,b'HTTP/1.1100(Continue)\r\n\r\n'],zmq.SNDMORE)
    content_length=int(标题['content-length'])
    打印(“等待接收%ikB正文”)
    而sum(len(chunk)表示块中的块)
    这种情况下的相关逻辑在
    recv_body
    方法中,该方法读取头并继续recv body的块,直到完成


    坦率地说,我认为使用ZMQ_流在Python中编写HTTP服务器没有多大意义。您可以将zmq套接字与现有的PythonEventLoops集成,并重用已经建立的HTTP库,因此您不必重新发明这个特殊的轮子。例如,pyzmq与tornado eventloop配合得特别好,您可以在同一个应用程序中同时使用zmq套接字和tornado http处理程序。

    此列表来自何处?这似乎不是文章的一部分。你能发布代码复制吗?@SlaterTyranus抱歉!发布了相关的信息。我只是将所有消息部分聚合到一个列表中。我发现了一个例子,这是在zeromq系统中集成http端点的好方法吗?是的,这正是那个例子想要说明的——使用tornado和zmq一起构建一个web应用程序。但它更复杂,不是吗?多个客户端意味着您可能会从每个交错的客户端接收部分。
    from traceback import print_exc
    import zmq
    from tornado.httputil import HTTPHeaders
    
    class BadRequest(Exception):
        pass
    
    class ConnectionLost(Exception):
        pass
    
    def parse_request(request):
        """Parse a request verp, path, and headers"""
        first_line, header_lines = request.split(b'\r\n', 1)
        verb, path, proto = first_line.decode('utf8').split()
        headers = HTTPHeaders.parse(header_lines.decode('utf8', 'replace'))
        return verb, path, headers
    
    
    def recv_body(socket, headers, chunks, request_id):
        """Receive the body of a request"""
        if headers.get('expect', '').lower() == '100-continue':
            if 'Content-Length' not in headers:
                # Don't support chunked transfer: http://tools.ietf.org/html/rfc2616#section-3.6.1
                print("Only support specified-length requests")
                socket.send_multipart([
                    request_id, b'HTTP/1.1 400 (Bad Request)\r\n\r\n',
                    request_id, b'',
                ])
                msg = 1
                while msg != b'':
                    # flush until new connection
                    _, msg = socket.recv_multipart()
                raise BadRequest("Only support specified-length requests")
    
            socket.send_multipart([request_id, b'HTTP/1.1 100 (Continue)\r\n\r\n'], zmq.SNDMORE)
    
            content_length = int(headers['Content-Length'])
            print("Waiting to receive %ikB body" )
            while sum(len(chunk) for chunk in chunks) < content_length:
                id_, msg = socket.recv_multipart()
                if msg == b'':
                    raise ConnectionLost("Disconnected")
                if id_ != request_id:
                    raise ConnectionLost("Received data from wrong ID: %s != %s" % (id_, request_id))
                chunks.append(msg)
        return b''.join(chunks)
    
    
    print(zmq.__version__, zmq.zmq_version())
    
    
    socket = zmq.Context().socket(zmq.STREAM)
    socket.bind("tcp://*:5555")
    
    
    while True:
        # Get HTTP request
        request_id, msg = socket.recv_multipart()
        if msg == b'':
            continue
        chunks = []
        try:
            request, first_chunk = msg.split(b'\r\n\r\n', 1)
            if first_chunk:
                chunks.append(first_chunk)
            verb, path, headers = parse_request(request)
            print(verb, path)
            print("Headers:")
            for key, value in headers.items():
                print('  %s: %s' % (key, value))
            body = recv_body(socket, headers, chunks, request_id)
            print("Body: %r" % body)
        except BadRequest as e:
            print("Bad Request: %s" % e)
        except ConnectionLost as e:
            print("Connection Lost: %s" % e)
        except Exception:
            print("Failed to handle request", msg)
            print_exc()
            socket.send_multipart([
                request_id, b'HTTP/1.1 500 (OK)\r\n\r\n',
                request_id, b''])
        else:
            socket.send_multipart([
                request_id, b'HTTP/1.1 200 (OK)\r\n\r\n',
                request_id, b''])