@use_kwargs 改变响应内容
@use_kwargs changes response content
我注意到 flask-apispec
中的 @use_kwargs
更改了响应内容类型。在下面的“hello world”示例中,@use_kwargs
的使用将响应内容类型从 text/html
更改为 application/json
。我发现它有点令人惊讶,因为 flask-apispec doc 没有提到它,我不希望注入 args 也会改变响应类型:
from flask import Flask
from flask_apispec import use_kwargs
from marshmallow import fields
app = Flask(__name__)
@app.route('/')
@use_kwargs({'email': fields.Str()}, location="query")
def hello_world(**kwargs):
return 'Hello, World!
curl -v http://127.0.0.1:5000/\?email\=abc
显示响应
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 16
< Server: Werkzeug/1.0.1 Python/3.8.2
< Date: Tue, 12 Jan 2021 06:09:25 GMT
<
"Hello, World!"
请注意 Content-Type: application/json
和值 hello world 被引用。然而,
没有 @use_kwargs
的行,响应是 Content-Type: text/html
并且内容 hello world 没有被引用:
~ curl -v http://127.0.0.1:5000/\?email\=abc
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 13
< Server: Werkzeug/1.0.1 Python/3.8.2
< Date: Tue, 12 Jan 2021 06:09:42 GMT
<
* Closing connection 0
Hello, World!%
更改响应的理由是什么?即使使用 @use_kwargs
,如何设置“text/html”的响应内容类型?谢谢!
更新:
只需在@Diego Miguel 给出的答案中添加更多细节:
改变内容的效果是由Wrapper.call
中的逻辑造成的
def __call__(self, *args, **kwargs):
response = self.call_view(*args, **kwargs)
if isinstance(response, werkzeug.Response):
return response
rv, status_code, headers = unpack(response)
mv = self.marshal_result(rv, status_code)
response = packed(mv, status_code, headers)
return flask.current_app.make_response(response)
marshal_result
使用“application/json” mimetype 调用 flask.jsonify which makes a Response 对象,并且还引入了上面“hello world”示例的额外引用级别。
我不完全确定为什么使用 @use_kwargs
会更改内容类型。通过查看 source code, it seems to return a dict
, judging by this function (that is called by activate
). So my best guess is that Flask when executing app.route
jsonifys that dict
, as that the default behaviour。此时,content-type
更改为 application/json
。但是,hello_world
是在use_kwargs
之后执行的,最后返回的是一个字符串,即“Hello World!”。
无论如何,我不认为这种行为实际上是flask-apispec
。
您可以更改响应(以及任何其他字段)的 content-type
,使用 make_reponse
创建一个 Flask.Response
对象,然后将其 content-type
设置为 "text/html"
(但是,这是在将字符串传递给 make_response
时默认设置的,因此没有必要):
from flask import Flask, make_response
from flask_apispec import use_kwargs
from marshmallow import fields
app = Flask(__name__)
@app.route('/')
@use_kwargs({'email': fields.Str()}, location="query")
def hello_world(**kwargs):
response = make_response("Hello World!")
response.content_type = 'text/html' # can be omitted
return response
curl -v http://127.0.0.1:5000/\?email\=abc
的输出:
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html
< Content-Length: 13
< Server: Werkzeug/1.0.1 Python/3.9.1
< Date: Tue, 12 Jan 2021 19:08:05 GMT
<
Hello World!
我注意到 flask-apispec
中的 @use_kwargs
更改了响应内容类型。在下面的“hello world”示例中,@use_kwargs
的使用将响应内容类型从 text/html
更改为 application/json
。我发现它有点令人惊讶,因为 flask-apispec doc 没有提到它,我不希望注入 args 也会改变响应类型:
from flask import Flask
from flask_apispec import use_kwargs
from marshmallow import fields
app = Flask(__name__)
@app.route('/')
@use_kwargs({'email': fields.Str()}, location="query")
def hello_world(**kwargs):
return 'Hello, World!
curl -v http://127.0.0.1:5000/\?email\=abc
显示响应
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 16
< Server: Werkzeug/1.0.1 Python/3.8.2
< Date: Tue, 12 Jan 2021 06:09:25 GMT
<
"Hello, World!"
请注意 Content-Type: application/json
和值 hello world 被引用。然而,
没有 @use_kwargs
的行,响应是 Content-Type: text/html
并且内容 hello world 没有被引用:
~ curl -v http://127.0.0.1:5000/\?email\=abc
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.64.1
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 13
< Server: Werkzeug/1.0.1 Python/3.8.2
< Date: Tue, 12 Jan 2021 06:09:42 GMT
<
* Closing connection 0
Hello, World!%
更改响应的理由是什么?即使使用 @use_kwargs
,如何设置“text/html”的响应内容类型?谢谢!
更新:
只需在@Diego Miguel 给出的答案中添加更多细节: 改变内容的效果是由Wrapper.call
中的逻辑造成的 def __call__(self, *args, **kwargs):
response = self.call_view(*args, **kwargs)
if isinstance(response, werkzeug.Response):
return response
rv, status_code, headers = unpack(response)
mv = self.marshal_result(rv, status_code)
response = packed(mv, status_code, headers)
return flask.current_app.make_response(response)
marshal_result
使用“application/json” mimetype 调用 flask.jsonify which makes a Response 对象,并且还引入了上面“hello world”示例的额外引用级别。
我不完全确定为什么使用 @use_kwargs
会更改内容类型。通过查看 source code, it seems to return a dict
, judging by this function (that is called by activate
). So my best guess is that Flask when executing app.route
jsonifys that dict
, as that the default behaviour。此时,content-type
更改为 application/json
。但是,hello_world
是在use_kwargs
之后执行的,最后返回的是一个字符串,即“Hello World!”。
无论如何,我不认为这种行为实际上是flask-apispec
。
您可以更改响应(以及任何其他字段)的 content-type
,使用 make_reponse
创建一个 Flask.Response
对象,然后将其 content-type
设置为 "text/html"
(但是,这是在将字符串传递给 make_response
时默认设置的,因此没有必要):
from flask import Flask, make_response
from flask_apispec import use_kwargs
from marshmallow import fields
app = Flask(__name__)
@app.route('/')
@use_kwargs({'email': fields.Str()}, location="query")
def hello_world(**kwargs):
response = make_response("Hello World!")
response.content_type = 'text/html' # can be omitted
return response
curl -v http://127.0.0.1:5000/\?email\=abc
的输出:
> GET /?email=abc HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.74.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html
< Content-Length: 13
< Server: Werkzeug/1.0.1 Python/3.9.1
< Date: Tue, 12 Jan 2021 19:08:05 GMT
<
Hello World!