CakePHPでContent-Lengthヘッダーが付かないときの原因と対処法


CakePHPで開発をしていると、APIレスポンスに Content-Length ヘッダーが付かずに困ることがあります。本記事では、Content-Length が付与される条件や、それを妨げている要因、対策方法を詳しくまとめます。


Content-Length を付与させる条件と方法

1. Apache に削除させない

.htaccess000-default.conf に以下の記述があると、Apacheが Content-Length を明示的に削除してしまいます。不要であれば削除しましょう。

Header unset Content-Length
Header set Transfer-Encoding "chunked"

2. Transfer-Encoding: chunked を無効にする

チャンク転送が有効だと Content-Length は使われません。無効にするには以下のように設定します。

Header unset Transfer-Encoding
SetEnv no-gzip 1

3. PHP側で出力サイズを明示する

単純なPHPスクリプトの場合:

<?php
$data = "Hello World!";
header('Content-Length: ' . strlen($data));
echo $data;

CakePHPのコントローラーで明示的に設定:

$this->response = $this->response
    ->withHeader('Content-Length', strlen($this->response->getBody()));

4. output_buffering を有効にする

php.ini でバッファリングを有効にしておくと、出力サイズを自動検出して Content-Length を付けてくれます。

output_buffering = 4096

あるいは:

output_buffering = On

Docker使用時は /usr/local/etc/php/php.ini などの場所にも注意してください。

5. mod_deflate / gzip の影響を防ぐ

圧縮が有効だと Transfer-Encoding に変わり Content-Length が除外されることがあります。

SetEnv no-gzip 1

チェックコマンド一覧

curl -i http://cakephp.test/
apachectl -M | grep headers
php -i | grep output_buffering

レスポンスに Content-Length: XXX が含まれていれば、付与は成功しています。


Content-Length を付けたい理由

  • CDNやロードバランサーでキャッシュ制御をしたい
  • クライアント側で進捗バーを表示したい
  • セキュリティポリシーやWAFでの要件に対応したい

よくある表示されない理由とその確認方法

1. レスポンスボディが空またはnull

本文が何も出力されていないと、Content-Length は出力されません。

確認方法:

curl -i http://cakephp.test/

2. ApacheがFastCGIで動作している

mod_php ではなく FastCGI や php-fpm 経由で動作していると Content-Length が省略されることがあります。

確認方法:

apachectl -V | grep -i mpm

または phpinfo()Server API を確認(例:FPM/FastCGI)


3. Dockerリバースプロキシの影響

nginxTraefik などがプロキシとして動作していると、ヘッダーが上書きされている可能性があります。

確認方法:

docker-compose ps

4. PHPが自動でchunked転送に切り替えている

バッファが使われていないと Content-Length を使わず Transfer-Encoding: chunked に切り替わることがあります。

対策例:

ob_start();
echo "Content";
$output = ob_get_clean();
header('Content-Length: ' . strlen($output));
echo $output;

5. CakePHPがキャッシュ制御をしている

CakePHP の withDisabledCache() やミドルウェアでキャッシュ制御が行われていると Content-Length が抑制される場合があります。


6. HTTP/2使用時にcurlで表示されない

HTTP/2ではフレーム単位で通信されるため、Content-Length が表示されなくても正常です。

HTTP/1.1を指定して確認:

curl -i --http1.1 http://cakephp.test/

7. PHPで出力前にWarningやNoticeが発生している

ヘッダー送信前にエラー出力があると、Content-Length が送信されないことがあります。


最終確認:ヘッダー送信のテンプレートスクリプト

CakePHPを通さずに info.php のようなスクリプトを用意し、最小構成で確認します。

<?php
$data = "Test Content";
header('Content-Length: ' . strlen($data));
echo $data;
curl -i http://cakephp.test/info.php

チェックリストまとめ

項目チェック内容
レスポンスが空でないか本文ありであることを確認
PHPモードの確認mod_php or php-fpm をチェック
Proxyによる上書きnginx, Traefik などが動作していないか
Transfer-Encoding の有無curl --http1.1 で確認
CakePHPのミドルウェアキャッシュ制御が有効か
HTTP/2 の仕様curl --http1.1 でフォールバックして確認
Apacheモジュールmod_headers, mod_deflate などの有無
PHPバッファ設定output_buffering, zlib.output_compression を確認

さいごに

Apacheの設定、PHPの動作モード、CakePHPの挙動などが複雑に絡み合うため、状況によって対策が異なります。
もし可能であれば 000-default.confDockerfile、CakePHPのコントローラーコードなどを共有していただければ、原因を特定しやすくなります。お気軽にご相談ください。

Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です