想让所有响应都带一个头、让视图直接返回 dataclass 或 Pydantic 对象,该改哪里?自定义 Response 类能做到什么、做不到什么?这篇踩一遍坑,再给出能用的写法。
默认 response_class,视图返回 User 对象 → 500 make_response 的报错: The view function did not return a valid response. The return type must be a string, dict, list, tuple with headers or status, Response instance, or WSGI callable, but it was a User.
上一篇:JSON Response 的序列化;下一篇:Streaming Response。make_response 的返回值规则见make_response() 的响应转换过程。
源码:
1 | class ApiResponse(Response):
2 | default_mimetype = "application/json"
3 | @classmethod
4 | def force_type(cls, response, environ=None):
5 | if isinstance(response, (User, Pyd)): ... # 转成 JSON 响应
6 | return super().force_type(response, environ)
7 | def __init__(self, *a, **kw): super().__init__(*a, **kw); self.headers["X-Api-Version"] = "1"
8 | app.response_class = ApiResponse
GET /user → 500 text/html; charset=utf-8 | X-Api-Version=1 X-T=None | '<!doctype html>\n<html lang=en>\n<title>500 Internal Server Er'
GET /pyd → 500 text/html; charset=utf-8 | X-Api-Version=1 X-T=None | '<!doctype html>\n<html lang=en>\n<title>500 Internal Server Er'
GET /str → 200 application/json | X-Api-Version=1 X-T=None | 'plain string'
GET /dict → 200 application/json | X-Api-Version=1 X-T=None | '{"k":"v"}'
GET /tuple → 500 text/html; charset=utf-8 | X-Api-Version=1 X-T=None | '<!doctype html>\n<html lang=en>\n<title>500 Internal Server Er'
GET /missing → 404 text/html; charset=utf-8 | X-Api-Version=1 X-T=None | '<!doctype html>\n<html lang=en>\n<title>404 Not Found</title>\n'500 页: 500 text/html; charset=utf-8 1
返回 str → 200 | force_type 被调用:[] 返回 dict → 200 | force_type 被调用:[] 返回 Response → 200 | force_type 被调用:['Response'] 返回 werkzeug Response → 200 | force_type 被调用:['Response'] 返回 WSGI callable → 200 | force_type 被调用:['function']
GET /user → 200 application/json | X-T=None | '{"id":1,"name":"\\u5f20\\u4e09"}'
GET /pyd → 200 application/json | X-T=None | '{"a":1}'
GET /tuple → 201 application/json | X-T=1 | '{"id":2,"name":"b"}'
GET /str → 200 text/html; charset=utf-8 | X-T=None | 'plain' Csv("a,b") → text/csv; charset=utf-8
Csv("a,b", mimetype="text/plain") → text/plain; charset=utf-8
Csv("a,b", content_type="text/tab-separated-values") → text/tab-separated-values