看不到 `asyncio.Transport.write()` 的任何效果

Can't see any effect of `asyncio.Transport.write()`

我正在尝试使用 asyncio 制作一个简单的自制本地主机 TCP 服务器(它只有 Python 3.6.9,因为我在这台机器上只有一个 LTS Ubuntu):

import asyncio
import socket
import urllib.parse
from http.server import BaseHTTPRequestHandler
from io import BytesIO

class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = BytesIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()
        rpc_request = urllib.parse.urlparse(self.path)
        self.endpoint = rpc_request.path
        self.query = urllib.parse.parse_qs(rpc_request.query)

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message


class Srv(asyncio.Protocol):
    def __init__(self, address=('127.0.0.1', 12345), family=socket.AF_INET, loop: asyncio.AbstractEventLoop=None):
        self._address = address
        self._family = family
        self._loop = loop if loop is not None else asyncio.get_event_loop()
        self._server = None

    def connection_made(self, transport):
        self._transport = transport

    def data_received(self, data):
        request = HTTPRequest(data)
        print("\tQuery:", request.query)
        self._transport.write(b'Hi!')
        self._transport.close()

    def eof_received(self):
        pass

    def factory(self):
        return self

    async def run(self):
        sock = socket.socket(family=self._family)
        sock.bind(self._address)
        sock.listen()
        if self._family == socket.AF_UNIX:
            self._server = await self._loop.create_unix_server(protocol_factory=self.factory, sock=sock)
        else:
            self._server = await self._loop.create_server(protocol_factory=self.factory, sock=sock, family=self._family)
        self._running = True

omg = Srv()

async def wat():
    await omg.run()
    await omg._server.wait_closed()

try:
    asyncio.get_event_loop().run_until_complete(wat())
except:
    omg._server.close()

好像可以启动甚至接收数据:

$ python3 0_o.py 
    Query: {'data': ['"abcd"']}
    Query: {'data': ['"abcd"']}

(打印是从 Srv.data_received 完成的),但 curl 说它没有收到它的响应:

$ curl '127.0.0.1:12345/query?data="abcd"'
curl: (52) Empty reply from server
$ curl '127.0.0.1:12345/query?data="abcd"'
curl: (52) Empty reply from server

从我的角度来看,我已经重新实现了 python 的 stdlib 文档中的 echo 服务器示例中的所有内容,但显然 data_received() 中的 write()close() 没有好像没什么效果。

我错过了什么?

据我所知,您的代码唯一的问题是您没有发出正确的 HTTP 响应,而只是发出字符串 "Hi"。例如,运行 您的代码未更改并将其连接到 nc 结果如下:

$ nc localhost 12345
GET / HTTP/1.0
Hi!

请注意,不仅没有正确的响应,而且服务器甚至没有等待客户端完成请求。相反,它立即打印出格式错误的响应。

curl 连接导致以下输出:

$ curl http://localhost:12345/
curl: (1) Received HTTP/0.9 when not allowed

"HTTP/0.9" 指的是 HTTP 协议的一个古老版本,其中状态行是可选的。此响应被 curl 拒绝,但 Wget 将接受它:

$ wget -qO- http://localhost:12345/
Hi!

与其尝试手动实施 HTTP,您可以查看一个为您完成的库,例如 aiohttp