Apacheの「406 Not Acceptable」のエラーについて。
このエラーは情報が少なく、遭遇して調べたいときにど忘れしていると調べる事に時間がかかって困るので備忘録的なメモです。
目次
1.406エラーとは
2.406エラーが発生する条件
3.他に406になる状況
4.406を回避しつつ拡張子無しで実行したい場合
406エラーとは
リクエストを受けたサーバーがコンテンツネゴシエーションをうまく行えず、どのコンテンツを処理するかがURIから判断できなかった時に発生。
406エラーが発生する条件
ApacheのOptions
の値を変えてphpやhtmlを拡張子無しで実行できる設定にすると、コンテンツネゴシエーションのエラーが出る様になります。
.httacess
を使う設定とは別の方です。
●再現方法
1.Apacheの設定のOptions
にMultiViews
を追加し、リクエストに対して扱うメディア種類の判断を自動で行うようにする
Options Indexes FollowSymLinks MultiViews
2.Apacheの設定のAddType
でメディア種別と実際に扱うファイル拡張子を紐づける
(これで拡張子を省略したURLで動くようになる)
AddType text/html .php
3.AddType
の設定を無視したMIMEタイプをHTTPヘッダのAccept
に設定し、拡張子を省略したURLで上記の設定をしたサーバーにリクエストをする
curl -i -H 'Content-Type: html/text' -H 'Accept: application/zip' 'http://localhost/php_index'
4.コンテンツネゴシエーションのエラーになる
※この時、リクエストはApacheで止められてURLで指定したファイルは実行されない
HTTP/1.1 406 Not Acceptable
Date: Mon, 11 Mar 2024 04:06:30 GMT
Server: Apache/2.4.58 (Fedora Linux)
Alternates: {"php_index.php" 1 {type text/html}}
Vary: negotiate
TCN: list
Content-Length: 350
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>406 Not Acceptable</title>
</head><body>
<h1>Not Acceptable</h1>
<p>An appropriate representation of the requested resource could not be found on this server.</p>
Available variants:
<ul>
<li><a href="php_index.php">php_index.php</a> , type text/html</li>
</ul>
</body></html>
だいたい上記の設定とリクエストの組み合わせで発生します。
そのため、406エラーが発生した時は発生したリクエストのhttpヘッダの内容とURL、そしてApacheの設定を確認する流れになります。
他に406になる状況
ModSecurityというオープンソースのファイアウォールを導入している場合も、設定ルールに反するリクエストで発生することがある様です。
(ModSecurityはあまり詳しくないので省略…)
406を回避しつつ拡張子無しで実行したい場合
どうしても拡張子無しでApacheに処理させたい場合は.htaccess
が有効です。
ただし、この方法は複雑な事をしたい場合RewriteRule
の書き方を工夫する必要があり、複雑になりがちです。
また、すでにApacheのOptions
にMultiViews
が設定されていたら干渉するのでApacheの設定からMultiViews
を削除する必要があります。
htaccessの例
●一番シンプルなもの
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]
/xxxxx
を /xxxxx.php
に置き換えます。
●/
で区切った値をパラメータとして受け取りたい場合
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^([^\/]*)/?(.*)? $1.php [L]
/xxxxx
または/xxxxx/
を/xxxxx.php
に置き換えつつ以降のパスは捨てます。
捨てた部分はリクエストパラメータとは別で取得します。
サーバーにURI情報が残るので、例えば、PHPなら$_SERVER['REQUEST_URI']
或いはfilter_input(INPUT_SERVER, 'REQUEST_URI')
で取得してパラメータとして利用します。