ESP8266(ESP-WROOM-02)の内容。ESP-WROOM-32ではないのでがおおよそ同じと思う。
現象
ESP8266のWiFiClientSecureでサーバからデータを取得しようとした。本来レスポンスの本体(ペイロード本文)は”[0]“を期待していたが以下の下3行のようにレスポンスが期待していたものと違う形になっていた。
Connecting to https://hoge.co.jp/api/fuga Connected to server Server: nginx Date: Wed, 21 Feb 2024 05:21:47 GMT Content-Type: text/html Transfer-Encoding: chunked Connection: close 3 [0] 0
理由
これはTransfer-Encoding: chunkedになっていてペイロード本文が
データ1のバイト数\r\nデータ1\r\n0\r\n
というフォーマットになっているため。長いもの送る場合は
データ1のバイト数\r\nデータ1\r\nデータ2のバイト数\r\nデータ2\r\n…データxのバイト数\r\nデータx\r\n…0\r\n
となる。なおデータのバイト数は16 進数表記。
対処
その1
対処としてそういうものとして読み込んでもよいけど、マルチバイトの場合データ1,2の間でぶった切られるのでつなげるのとか面倒。
その2
可能ならサーバ側で送る際にTransfer-Encoding: chunkedじゃなくしたい。
今回はサーバ側はpythonのBaseHTTPRequestHandlerを使っているがレスポンスにContent-Lengthをつけてやれば自動でTransfer-Encoding: chunkedじゃなくなった。「とりあえず、Content-Lengthついてないからchunkedでおくとっくわ」という仕様だったっぽい。(明示的にヘッダー付けた場合に消えるかは未確認)
from http.server import BaseHTTPRequestHandler, HTTPServer
from reserve_count import reserve_count
import urllib.parse
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed_path = urllib.parse.urlparse(self.path)
query_params = urllib.parse.parse_qs(parsed_path.query)
if parsed_path.path == '/api/reserve_count':
response_content = "ほげ".encode('utf-8')
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header('Content-Length', len(response_content))
self.end_headers()
http1.1の仕様的にはTransfer-Encoding: chunkedの時にはContent-Length不要らしい。