mod_rewrite送信しないことは異なります:compled-languageを書き直したときに一致します
-
02-10-2019 - |
質問
私は、受け入れ言語が存在しない場合 /誰かが訪問しようとする場合 / /にリダイレクトする書き直しルールを持っています ?lang=en
. 。返されたヘッダーを除いて、それは正常に動作します。 Vary: accept-language
応答から欠落しています。
RewriteCond %{HTTP:Accept-Language} ^$
RewriteCond %{QUERY_STRING} ^lang=en
RewriteRule ^$ http://www.example.com/? [R=301,L]
Apacheドキュメントは次のように指定します。
条件でHTTPヘッダーが条件で使用される場合、このヘッダーは、条件がリクエストに対してtrueに評価される場合に、応答の変化ヘッダーに追加されます。条件がリクエストに対してfalseに評価された場合、それは追加されません。
条件は間違いなく一致し、リダイレクトされているので、Apacheが言語を追加していない理由がわかりません。プロキシがそれをキャッシュする場合、なぜこれが本当の問題になるのかを見ることができます。
解決
Apacheのリクエスト処理システムの怪しげな下腹を覗いた後、ドキュメントはやや誤解を招くことがわかりました...しかし、説明に入る前に、私がこのものでApacheに翻弄されていると言うことができます。
クライアントの問題
最初に、ヘッダー名はに追加されません 変化 クライアントから送信されない場合の応答ヘッダー。これは方法によるものです mod_rewrite
そのヘッダーの値を構築します 初めの.
名前でヘッダーを使用して検索します apr_table_get()
, 、リクエストのヘッダーテーブル、およびあなたが提供した名前:
const char *val = apr_table_get(ctx->r->headers_in, name);
もしも name
テーブルの鍵ではありません、この機能は返されます NULL
. 。これは問題です。これはすぐにチェックがあるからです val
:
if (val) {
// Set the structure member ctx->vary_this
}
ctx->vary_this
パーマで使用されますRewriteCond
ファイナルに組み立てる必要があるヘッダー名を蓄積する基礎 変化 ヘッダ*。値がない場合、割り当てやアプリが発生しないため、参照される(送信されていない)ヘッダーは Vary
. 。ドキュメントはこれを明示的に述べていないため、あなたが期待したものであったかもしれないし、そうではなかったかもしれません。
*脇として、 NV
(変化しない)フラグと無視中の機能機能は、設定によって実装されます ctx->vary_this
に NULL
, 、応答ヘッダーへの追加を防ぎます。
ただし、送信した可能性があります 告出を受け入れます, 、しかし、それは空白でした。この場合、空の文字列は上記のチェックに合格し、ヘッダー名が追加されます 変化 に mod_rewrite
上記のものから。これを念頭に置いて、私は次の要求を使用して、何が起こっているのか診断しました。
User-Agent: Fiddler Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Host: 129.168.0.123
これも機能しませんが、なぜですか? mod_rewrite
ルールと条件が一致するとき、間違いなくヘッダーを設定します(ctx->vary
の総計です ctx->vary_this
すべてのチェック条件にわたって):
if (ctx->vary) {
apr_table_merge(r->headers_out, "Vary", ctx->vary);
}
これは、ログステートメントで確認できます。 r->headers_out
は 応答ヘッダーを生成するときに使用される変数。しかし、何かが間違いなく間違っていることを考えると、規則が実行された後に問題があるに違いありません。
.htaccessの問題
現在、あなたはあなたのルールをで定義しているように見えます .htaccess
, 、またはa <Directory>
セクション。この意味は mod_rewrite
ApacheのFixupフェーズで動作しており、ここで実際に書き換えを実行するために使用するメカニズムは非常に乱雑です。あなたはそれがなくても問題がなかったので、1秒間外部リダイレクトがないと仮定しましょう(そして、私は後でリダイレクトで問題に到達します)。
書き換えを実行した後、モジュールの要求処理が実際にファイルにマッピングするには遅すぎます。代わりにそれが行うことは、リクエストの「コンテンツ」ハンドラーとしてそれ自体を割り当て、リクエストがそのポイントに到達すると、 ap_internal_redirect()
. 。これは、新しいリクエストオブジェクトの作成につながります。 headers_out
オリジナルからのテーブル。
仮定して mod_rewrite
それ以上のリダイレクトを引き起こすことはありません、応答はから生成されます 新着 リクエストオブジェクト。これには、適切な(元の)ヘッダーが割り当てられないことはありません。サーバーごとのコンテキストで(メイン構成または <VirtualHost>
)、 しかし...
リダイレクトの問題
残念ながら、たとえ私たちが使用していても、とにかくそれはほとんど無関係であることがわかります mod_rewrite
サーバーのコンテキストでは、リダイレクトの場合に応答が取るパスは、モジュールが設定されているヘッダーを引き起こします。
リクエストがApacheによって受信されたとき、一連の関数呼び出しを介してそれは ap_process_request()
. 。これは順番に呼び出します ap_process_request_internal()
, 、重要な要求解析手順の大部分が発生する場所(の呼び出しを含む mod_rewrite
)。整数ステータスコードを返します。これは、リダイレクトの場合、たまたま301に設定されます。
ほとんどのリクエストが返されます OK
(値は0です)、すぐに ap_finalize_request_protocol()
. 。しかし、それはそうです ここではそうではありません:
if (access_status == OK) {
ap_finalize_request_protocol(r);
}
else {
r->status = HTTP_OK;
ap_die(access_status, r);
}
ap_die()
追加の操作を行います(応答コードを301に戻すなど)。この特定のケースでは、 ap_send_error_response()
.
幸いなことに、これは最終的に問題の根源です。それはそのように思えるかもしれませんが、物事は「アスバックワード」ではなく、これは元のヘッダーの破壊を引き起こします。それについてのコメントさえあります ソースで:
if (!r->assbackwards) {
apr_table_t *tmp = r->headers_out;
/* For all HTTP/1.x responses for which we generate the message,
* we need to avoid inheriting the "normal status" header fields
* that may have been set by the request handler before the
* error or redirect, except for Location on external redirects.
*/
r->headers_out = r->err_headers_out;
r->err_headers_out = tmp;
apr_table_clear(r->err_headers_out);
if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {
if ((location != NULL) && *location) {
apr_table_setn(r->headers_out, "Location", location);
}
//...
}
//...
}
それに注意してください r->headers_out
交換され、元のテーブルがクリアされます。そのテーブルには、応答に表示されると予想されるすべての情報があったため、今では失われています。
結論
リダイレクトせず、サーバーごとのコンテキストでルールを定義する場合、すべてが正しく機能するようです。しかし、これはあなたが望むものではありません。潜在的な回避策を見ることができますが、サーバーを再コンパイルする必要性は言うまでもなく、それが受け入れられるかどうかはわかりません。
As for the Vary: Accept-Encoding
, 、ヘッダーが忍び寄ることを可能にする方法で動作する別のモジュールから来ると仮定することができます。理由もわかりません ガンボ 試してみると問題はありませんでした。
参照のために、私は2.2.14と 2.2トランクソースコード, 、そして、私はApache 2.2.15を変更して実行していました。関連するコードセクションのバージョン間に大きな違いはないようです。
他のヒント
次のようなものを回避策として試してみることができます。
<LocationMatch "^.*lang\=">
Header onsuccess merge Vary "Accept-Language"
</LocationMatch>