HTTP の レスポンスヘッダー を json.dumps しようと思いはまったので記事を書いてみました。
単純にレスポンスの結果を表示してみる。
import requests
req = requests.get(url='http://example.com')
print(req.headers)
実行結果
{'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '11', 'Server': 'Werkzeug/0.14.1 Python/3.6.4', 'Date': 'Thu, 08 Mar 2018 10:13:52 GMT'}
正常に動作したのでJSONで出力してみる。 json.dumps で出力できるはず。
import requests, json
req = requests.get(url='http://example.com')
print(json.dumps(req.headers))
実行結果
Traceback (most recent call last):
File "test.py", line 7, in <module>
print(json.dumps(req.headers))
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/Cellar/python3/3.6.4_2/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
o.__class__.__name__)
TypeError: Object of type 'CaseInsensitiveDict' is not JSON serializable
なんでや!!なんでなんや!! CaseInsensitiveDict は JSON serializable できないと怒られています。 requests.response.headers はただのdictではなくCaseInsensitiveDict という型で 、json.dumps に対応していない型らしい。 型をdictにするとうまくいく。
import requests, json
req = requests.get(url='http://example.com')
print(json.dumps(dict(req.headers)))
実行結果
{"Content-Encoding": "gzip", "Accept-Ranges": "bytes", "Cache-Control": "max-age=604800", "Content-Type": "text/html", "Date": "Thu, 08 Mar 2018 10:23:24 GMT", "Etag": "\"1541025663+gzip\"", "Expires": "Thu, 15 Mar 2018 10:23:24 GMT", "Last-Modified": "Fri, 09 Aug 2013 23:54:35 GMT", "Server": "ECS (pae/3796)", "Vary": "Accept-Encoding", "X-Cache": "HIT", "Content-Length": "606"}
なぜこんなことをするのか… API Gateway から Lambda 実行した際に response は以下の形式の辞書型を返します。
{
'statusCode': statusCode,
'headers': headers ,
'body': body
}
requests.response の結果をただ返すと、Lambda の方で 関数の response を json.dumps しているようで、return した後に同様のエラーに遭遇します。
An error occurred during JSON serialization of response: {'Content-Encoding': 'gzip', 'Content-Type': 'application/json;charset=UTF-8', 'Date': 'Thu, 08 Mar 2018 09:21:06 GMT', 'Server': 'Apache-Coyote/1.1', 'Vary': 'Accept-Encoding', 'X-Application-Context': 'pine-movie-api', 'Content-Length': '700', 'Connection': 'keep-alive'} is not JSON serializable
Traceback (most recent call last):
File "/var/lang/lib/python3.6/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/var/lang/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/var/lang/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/var/runtime/awslambda/bootstrap.py", line 110, in decimal_serializer
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: {'Content-Encoding': 'gzip', 'Content-Type': 'application/json;charset=UTF-8', 'Date': 'Thu, 08 Mar 2018 09:21:06 GMT', 'Server': 'Apache-Coyote/1.1', 'Vary': 'Accept-Encoding', 'X-Application-Context': 'recochoku-api', 'Content-Length': '700', 'Connection': 'keep-alive'} is not JSON serializable
そのため requests.response.header を dict 型に変換する必要がありました。
高橋克幸
新卒3年目で脱新人を目指してます。
フロントに興味を持ち始めた今日このごろ。
趣味は 麻雀 プログラミング 音楽。
運動不足を感じているため、ダンスを始めようかと思っています。