2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Google App Engine上でFlaskを利用してNo Content(204)を返すとき、 ```Content-Length``` が0じゃないとエラーになる

Posted at

概要

前回、Google App EngineでFlaskを利用する際のNo Content(204)ステータスコードの利用方法を調査したけれど、原因がいまいち特定できていませんでした。
原因がわかりました!:clap:

Google App Engine上のFlaskでレスポンスをNo Content(204)で返す方法を調べた
https://qiita.com/kai_kou/items/801ae9715b5b8f4736b8

原因

No Content(204)を返すとき、Content-Length0 じゃないと、GAEでgunicornプロセスが落ちる(白目

検証

前回の記事のソースを利用して検証します。

GitHubにもソースをアップしていますので、ご参考ください。
https://github.com/kai-kou/how-to-use-gae-no-content

環境設定
> git clone https://github.com/kai-kou/how-to-use-gae-no-content.git
> cd how-to-use-gae-no-content
> python -m venv venv
> . venv/bin/activate
> pip install -r requirements.txt

環境が用意できたらflaskを起動します。

> flask run

curl で確認してみます。

flask_runしていないコンソール
> curl 127.0.0.1:5000/good_no_content -i
HTTP/1.0 204 NO CONTENT
Content-Type: application/json
Content-Length: 0
Server: Werkzeug/0.14.1 Python/3.6.6

> curl 127.0.0.1:5000/bad_no_content -i
HTTP/1.0 204 NO CONTENT
Content-Type: application/json
Content-Length: 5
Server: Werkzeug/0.14.1 Python/3.6.6

はい。GAEにもデプロイしています。
GitHubからソース取得している場合、app.yamlservice を変更するか削除してください。

> touch app.yaml
> gcloud app deploy

デプロイできたら確認してみます。

> curl https://[GAEのサービス名]-dot-[GCPのプロジェクトID].appspot.com/good_no_content -i
HTTP/2 204
content-type: application/json
x-cloud-trace-context: 436098c2c9196bd34b10448cb57643b0;o=1
server: Google Frontend
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"

> curl https://[GAEのサービス名]-dot-[GCPのプロジェクトID].appspot.com/bad_no_content -i
HTTP/2 500
x-cloud-trace-context: 0f98972aa581c03afa7af2d39596b8af;o=1
content-type: text/html; charset=UTF-8
server: Google Frontend
content-length: 323
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
()

はい。bad_no_content はやはりエラーになります。

前回はHTTPステータスコードとContent-Type しかみてなかったのですが、ローカル実行時のContent-Length に違いがあることのがわかりました。

# Good
Content-Length: 0

# Bad
Content-Length: 5

そのへんから情報を漁っていると、Flask-RESTfulというライブラリのGitHubにそれらしきIssueがありました。。。

204 status returns non-zero content-length
https://github.com/flask-restful/flask-restful/issues/736

試しに、だめな方の実装を変更してみます。headersContent-Length を追加します。

app.py(一部)
# GAEでエラーになる
@app.route('/bad_no_content', methods=['GET'])
def bad_no_content():
  response = make_response(jsonify(None), 204)
  response.headers['Content-Length'] = 0
  return response

> flask run
flask_runしていないコンソール
> curl 127.0.0.1:5000/bad_no_content -i
HTTP/1.0 204 NO CONTENT
Content-Type: application/json
Content-Length: 0
Server: Werkzeug/0.14.1 Python/3.6.6

GAEにデプロイして確認します。

> gcloud app deploy

> curl https://[GAEのサービス名]-dot-[GCPのプロジェクトID].appspot.com/bad_no_content -i
HTTP/2 204
content-type: application/json
x-cloud-trace-context: b26c9b04d914cbc0e38de16f8d7fe28f;o=1
server: Google Frontend
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"

おぅ。。。エラーが発生しなくなりましたぁぁぁ。

嫌がらせに以下のように変更して実行してみます。コンテンツを明示的に返すようにします。

app.py(一部)
# GAEでエラーになる
@app.route('/bad_no_content', methods=['GET'])
def bad_no_content():
  # コンテンツを設定してみる
  response = make_response(jsonify({'message':'hoge'}), 204)
  response..headers['Content-Length'] = 0
  return response

> flask run
flask_runしていないコンソール
> curl 127.0.0.1:5000/bad_no_content -i
HTTP/1.0 204 NO CONTENT
Content-Type: application/json
Content-Length: 0
Server: Werkzeug/0.14.1 Python/3.6.6

GAEにデプロイして確認します。

> gcloud app deploy

> curl https://[GAEのサービス名]-dot-[GCPのプロジェクトID].appspot.com/bad_no_content -i
HTTP/2 204
content-type: application/json
x-cloud-trace-context: 27edb7f43586aec504497cc61b46be4d
date: Tue, 30 Oct 2018 08:48:21 GMT
server: Google Frontend
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"

ヘッダー優先みたいですね。

ついでに''None とでレスポンス内容の際をみてみました。
jsonify を利用すると改行が入ってしまう模様。イラナイヨォ
Nonenull に変換されます。

レスポンス実装 レスポンス内容
make_response('', 204).data b''
make_response(None, 204).data エラー
make_response(jsonify(''), 204).data b'""\n'
make_response(jsonify(None), 204).data b'null\n'

make_responseが面倒だ!

make_response を利用せず、以下のように実装することもできます。

headers = {
  'Content-Type': app.config['JSONIFY_MIMETYPE'],
  'Content-Length': 0
}
return '', 204, headers

まとめ

No Content(204)を返すとき、Content-Length0 じゃないと、GAEでgunicornプロセスが落ちるから気をつけましょう(再掲

前回は原因不明のまま、回避策だけを見出して終わったのですが、今回、なんとか原因がわかって、モヤモヤが晴れました^^

こういった問題が起こり得るので、Dockerイメージでほぼ同一環境!最強!ヒャッハーと油断しているといざクラウド環境に上げてから、痛い目に合いそうで(実際合った)怖いですね。

早めに運用環境で検証しておくのに越したことはないですね。教訓!

参考

204 status returns non-zero content-length
https://github.com/flask-restful/flask-restful/issues/736

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?