Flask:浏览器(或代理)发送了该服务器无法理解的请求

Flask: The browser (or proxy) sent a request that this server could not understand

我创建了一个小型 Flask 服务。但是,每次我尝试使用 say-hi 端点时,我都会收到以下消息:

{
    "message": "The browser (or proxy) sent a request that this server could not understand."
}

我的 Flask 服务如下所示:

from flask import Flask, request
from flask_restful import Resource, Api, abort, reqparse

app = Flask(__name__)
api = Api(app)

class HelloResource(Resource):
    def get(self):
        return { 'message': 'Hello' }

class SayHiResource(Resource):
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('name', required=True, help='Name cannot be blank')
        args = parser.parse_args()

        return { 'message': 'Hello ' + args['name'] }

api.add_resource(HelloResource, '/hello')
api.add_resource(SayHiResource, '/say-hi')

if __name__ == '__main__':
    app.run(debug=True, load_dotenv=True)

但是,关于失败原因的信息不多。

我 运行 的方式是使用 gunicornserviceEntrypoint.py 文件, 只有这个内容:

from src.api.service import app

if __name__ == '__main__':
    app.run()

这是我的文件夹结构

.
├── requirements.txt
├── serviceEntrypoint.py
└── src
    ├── __init__.py
    └── api
        ├── __init__.py
        └── service.py

为什么 /hello 结尾有效,但当我调用 http://localhost:8000/say-hi?name=Johnsay-hi 却无效?

如果您 运行 Flask 调试服务器并发出您的 HTTP 请求 http://localhost:8000/say-hi?name=John,您将看到实际错误是:

message "Did not attempt to load JSON data because the request Content-Type was not 'application/json'."

有文档和示例 here,但归结为选择请求应该是 GET 还是 POST。您构建请求的方式 - 您仅传递 1 个字段,用户名 - 它看起来像一个 GET,在这种情况下您应该:

api.add_resource(SayHiResource, '/say-hi/<username>')

和class:

class SayHiResource(Resource):
    def get(self, username):
        return { 'message': 'Hello ' + username }

如果您想实现 POST 请求,请在文档中跟踪调用触发的示例:curl http://localhost:5000/todos -d "task=something new" -X POST -v

更新:

使用查询参数,可以使用request.args:

api.add_resource(SayHiResource, '/say-hi')

class:

class SayHiResource(Resource):
    def get(self):
        username = request.args.get("username")
        status = request.args.get("status")
        # print(query_args)
        return { 'message': 'Hello {}, your status is: {}'.format(username, status) }

示例:

[http_offline@greenhat-35 /tmp/] > curl 'http://localhost:8000/say-hi?username=lala&status=enabled'
{
    "message": "Hello lala, your status is: enabled"
}
[http_offline@greenhat-35 /tmp/] > 

解决方法是添加location='args',这样reqparse只使用查询字符串值:

parser.add_argument('name', required=True, help='Name cannot be blank', location='args')

问题的原因是 Argument has 'json' as the default location and recent versions of Werkzeug (used by flask) will raise an exception when reqparse tries to read json data from the (non-json) request. This should probably be considered a bug in reqparse, but it's deprecated,所以不要指望更新。