代码之家  ›  专栏  ›  技术社区  ›  Jacobo

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

  •  0
  • Jacobo  · 技术社区  · 2 年前

    我创建了一个 Flask 服务然而,每次我尝试使用 say-hi 端点,我收到以下消息:

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

    我的烧瓶服务如下所示:

    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)
    

    然而,没有太多关于失败原因的信息。

    我跑步的方式是 gunicorn 以及 serviceEntrypoint.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=John ?

    0 回复  |  直到 2 年前
        1
  •  2
  •   dbenton    2 年前

    解决方案是添加 location='args' ,因此reqparse只使用查询字符串值:

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

    问题的原因是 Argument 默认位置为“json”,当reqparse尝试从(非json)请求中读取json数据时,最新版本的Werkzeug(由flask使用)将引发异常。这可能应该被认为是reqparse中的一个错误,但它 deprecated ,所以不要指望更新。

        2
  •  1
  •   ilias-sp    2 年前

    如果运行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 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 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/] >