首页 > 解决方案 > 带 aiohttp TestClient 的多部分文件上传导致第二次请求出现“无效的 HTTP 方法”错误

问题描述

我继承了一个使用aiohttp我不熟悉的代码库。在尝试修改测试时,我发现连续上传两个多部分文件(不仅仅是表单)会导致服务器返回400 Bad status line 'invalid HTTP method'错误(但请参见下面的注释 1)。

向服务器方法添加await request.release()语句解决了该问题,但您不应该这样做

在这一点上,我很难过如何解决这个问题。我已将代码库缩减为这个最小的应用程序:

from aiohttp import web

routes = web.RouteTableDef()


@routes.post("/thing")
async def thing(request: web.Request):
    # await request.release()                       # uncommenting this line fixes the issue
    return web.json_response({"hey": "there"})


def app_factory():
    app = web.Application()
    app.router.add_routes(routes)
    return app

...还有这个最小的测试用例,它仍然很重要:

import asyncio
import os

from aiohttp import test_utils

import gdi.app_min as app

class AppClient:
    def __init__(self):
        self.server = test_utils.TestServer(app.app_factory())

    async def __aenter__(self):
        await self.server.start_server(loop=asyncio.get_event_loop())
        self.client = test_utils.TestClient(self.server, loop=asyncio.get_event_loop())
        return self.client

    async def __aexit__(self, *args):
        await self.server.close()
        await self.client.close()


async def test_upload():
    testdir = os.path.normpath(os.path.join(os.getcwd(), './temptest/'))
    os.makedirs(testdir, exist_ok=True)
    async with AppClient() as cli:
        await _do_thing(cli, testdir, "test_file_1")
        await _do_thing(cli, testdir, "test_file_2")


async def _do_thing(cli, testdir, filename):
    path = os.path.join(testdir, filename)
    with open(path, encoding="utf-8", mode="w") as f:
        f.write("testtext")

    # failure only occurs with file upload & no await request.release() in app
    # data={"uploads": "stuff"} is ok
    with open(path, "rb") as f:
        res = await cli.post("thing", data={"uploads": f})
    print(f'\n*** res for {filename} ***')
    print(await(res.text()))
    print(f"***")
    assert res.status == 200

这会导致 403 并且服务器在第二次调用时出现以下错误:

Error handling request
Traceback (most recent call last):
  File "/home/<user>/.local/share/virtualenvs/<dir>-YbLpo7lw/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 314, in data_received
    messages, upgraded, tail = self._request_parser.feed_data(data)
  File "aiohttp/_http_parser.pyx", line 546, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: 400, message="Bad status line 'invalid HTTP method'"

在这一点上,我花了一天时间阅读 aiohttp 文档试图弄清楚这一点,但我不太确定下一步该去哪里。任何意见,将不胜感激。

编辑:看起来这是一个已知的错误

注1:显然坏状态行错误具有误导性:https ://github.com/aio-libs/aiohttp/issues/3287#issuecomment-425008291

标签: pythonmultipartaiohttp

解决方案


推荐阅读