为什么Python中的Flask请求在没有Content-Type头时无法反序列化JSON POST数据?[duplicate]

5q4ezhmt  于 2023-01-10  发布在  Python
关注(0)|答案(1)|浏览(176)
    • 此问题在此处已有答案**:

(13个答案)
Get raw POST body in Python Flask regardless of Content-Type header(4个答案)
3天前关闭。
最小示例:

#!/usr/bin/env python3

import json
from dataclasses import dataclass

from flask import Flask, request, make_response
from flask_restful import Resource, Api

@dataclass
class Foo:
    bar: int

class WebController(Resource):
    def __init__(self, factor) -> None:
        self._factor = factor

    def post(self):
        foo = Foo(**json.loads(request.data))
        return make_response(str(self._factor * foo.bar), 200)

def main():
    app = Flask(__name__)
    api = Api(app)
    api.add_resource(WebController, "/json_post_endpoint", resource_class_kwargs={"factor": 2})
    app.run(port=8080)

if __name__ == "__main__":
    main()

运行它,然后发送一个不带标头的curl

curl -X POST --url http://localhost:8080/json_post_endpoint --data '{ "bar": 42 }'
{"message": "Internal Server Error"}

日志:

[2023-01-06 10:34:23,616] ERROR in app: Exception on /json_post_endpoint [POST]
Traceback (most recent call last):
  File "/home/tobias/.local/lib/python3.10/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/tobias/.local/lib/python3.10/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/home/tobias/.local/lib/python3.10/site-packages/flask_restful/__init__.py", line 467, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/tobias/.local/lib/python3.10/site-packages/flask/views.py", line 107, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)
  File "/home/tobias/.local/lib/python3.10/site-packages/flask_restful/__init__.py", line 582, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/home/tobias/Documents/main.py", line 20, in post
    foo = Foo(**json.loads(request.data))
  File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

但是有了标头,curl就可以了:

curl -X POST --url http://localhost:8080/json_post_endpoint --header 'Content-Type: application/json' --data '{ "bar": 42 }'
84

向请求添加标头会使服务器的行为发生什么变化?

xxhby3vn

xxhby3vn1#

你在做什么

json.loads(request.data)

注意到flask.request具有用于此的方法,即get_json
将数据解析为JSON。
如果mimetype不指示JSON(application/json,请参阅is_json),或者解析失败,则调用on_json_loading_failed()并将其返回值用作返回值。默认情况下,这会引发400 Bad Request错误。
参数

  • force(bool)-忽略mimetype并始终尝试解析JSON。
  • silent(bool)-隐藏mimetype和解析错误,并返回None。
  • cache(bool)-存储解析后的JSON,以便在后续调用时返回。

(...)
因此,如果希望将请求解析为JSON而不考虑头,则应该

request.get_json(force=True)

如果您不想关心所得到不是合法JSON或

request.get_json(force=True,silent=True)

然后准备好得到None,表示您得到了非法JSON。

相关问题