"keine akzeptable Variante" von MultiViews von Apache
In einer Implementierung einer PHP-basierten Anwendung, die Apache - MultiViews
option wird verwendet, um zu verbergen .php Erweiterung einer request-dispatcher-Skript. E. g. eine Anfrage an
/page/about
...würde behandelt werden, indem
/page.php
...mit dem hinteren Teil der Anfrage-URI verfügbar in PATH_INFO
.
Meisten der Zeit dies funktioniert gut, aber gelegentlich zu Fehlern führt wie
[error] [client 86.x.x.x] no acceptable variant: /path/to/document/root/page
Meine Frage ist: Was löst diesen Fehler gelegentlich und wie kann ich das problem beheben?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kurze Antwort
Dieser Fehler kann auftreten, wenn alle folgenden Punkte gleichzeitig erfüllt:
Erlauben Sie Multiviews zu dienen, PHP-Dateien, indem Sie Sie einen beliebigen Typ mit der
AddType
Richtlinie, die am ehesten mit einer Zeile wie dieser:Accept
header, die nicht*/*
als akzeptable MIME-type (dies ist sehr ungewöhnlich, das ist, warum Sie sehen die Fehler nur selten).MultiviewsMatch
Richtlinie festlegen, um den StandardwertNegotiatedOnly
.Können Sie den Fehler beheben, indem Sie den folgenden Zauberspruch deiner Apache config:
Erklärung
Verständnis, was Los ist, hier benötigt man mindestens einen oberflächlichen überblick über die Funktionsweise von Apache ' s
mod_negotiation
und HTTP istAccept
undAccept-Foo
Header. Vor schlagen die beschriebenen Fehler von der OP, ich wusste nichts über diese beiden; ich hattemod_negotiation
aktiviert ist, nicht durch bewusste Wahl, sondern weil das ist, wieapt-get
einrichten von Apache für mich, und ich aktiviert hatteMultiViews
ohne viel Verständnis für die Auswirkungen von, dass, abgesehen, dass es lassen Sie mich verlassen.php
am Ende meiner URLs. Ihre Umstände sein können, die ähnlich oder identisch.So, hier sind einige wichtige Grundlagen, die ich nicht wusste:
request-Header wie
Accept
undAccept-Language
lassen Sie den Kunden angeben, welche MIME-Typen oder Sprachen, es ist akzeptabel für Sie, um die Antwort zu erhalten, sowie die Angabe von gewichteten Präferenzen für die akzeptierten Typen oder Sprachen. (Das sind natürlich nur nützlich, wenn der server, oder ist der fähig ist, verschiedene Antworten, die basierend auf diesen Header.) Zum Beispiel, Chrom-sendet aus den folgenden Header für mich, wenn ich eine Seite zu laden:Apache
mod_negotiation
können Sie speichern mehrere Dateien wiemyresource.html.en
,myresource.html.fr
,myresource.pdf.en
undmyresource.pdf.fr
im gleichen Ordner und dann automatisch die AnfrageAccept-*
- Header, um zu entscheiden, denen zu dienen, wenn der client schickt eine Anfrage anmyresource
. Es gibt zwei Möglichkeiten, dies zu tun. Die erste ist das erstellen einer Type-Map Datei in den gleichen Ordner, der ausdrücklich erklärt, den MIME-Typ und Sprache, die für jede der verfügbaren Dokumente. Die andere ist die Verwendung von Multiviews.Wenn Multiviews aktiviert sind...
Die wichtige Sache zu beachten ist hier, dass die
Accept
header ist immer noch respektiert wird von der Apache auch mit Multiviews aktiviert; der einzige Unterschied besteht aus der type-map-Ansatz ist, dass der Apache Herleitung der MIME-Typen der Dateien, die von Datei-Erweiterungen, anstatt durch Sie explizit zu deklarieren, die in einer type-map.Den keine akzeptable Variante Fehler geworfen wird (und ein 406 gesendete Antworten) von Apache, wenn es existieren Dateien für die URL, die er erhalten hat, aber es ist nicht erlaubt, um zu dienen alle von Ihnen, weil Ihre MIME-Typen nicht mit den Möglichkeiten, die in der Anfrage
Accept
header. (Das gleiche kann passieren, wenn es zum Beispiel keine Variante in einer akzeptablen Sprache.) Dies ist konform mit der HTTP-spec, die besagt:Testen kann man dieses Verhalten leicht genug. Erstellen Sie einfach eine Datei namens
test.html
mit der Zeichenfolge "Hallo Welt" in der webroot des Apache-server mit Multiviews aktiviert, und dann versuchen Sie es mit einem Accept-header, die es erlaubt HTML-Antworten gegen eine, die nicht. Ich zeige das hier auf meinem lokalen (Ubuntu) Rechner mitcurl
:Dies bringt uns zu einer Frage, die wir noch nicht angesprochen: wie funktioniert
mod_negotiate
bestimmen Sie den MIME-Typ einer PHP-Datei bei der Entscheidung, ob es kann es dienen? Da die Datei ausgeführt und konnte, spuckte jederContent-Type
- header, die es liebt, den Typ noch nicht bekannt ist, vor der Ausführung.Gut, standardmäßig, die Antwort ist, dass MultiViews einfach nicht dienen
.php
- Dateien. Aber die Chancen sind, dass Sie Folgen den Rat von einem der vielen, vielen Beiträge im internet (ich bekomme eine 4 auf der ersten Seite, wenn ich Google 'php-apache multiviews', die top eindeutig das man die OP von dieser Frage gefolgt, da er eigentlich kommentiert es) befürworten die Fortbewegung dieser mit einem AddType header, vermutlich auf der Suche etwas wie dieses:Nicht wahr? Warum dieser magisch-Angabe veranlasst den Apache, um glücklich zu sein, zu dienen
.php
Dateien? Sicherlich Browsern nicht darunterapplication/x-httpd-php
als einer der Typen werden Sie akzeptieren, in IhrerAccept
Header?Nun, nicht genau. Aber alle großen haben auch
*/*
(und erlaubt somit eine Reaktion von jedem MIME - Typ-Sie sind mit derAccept
header nur für den Ausdruck von Präferenz Gewichtung nicht für die Einschränkung der Typen werden Sie akzeptieren.) Dies bewirkt, dassmod_negotiation
bereit sein, zu wählen und zu dienen.php
Dateien, solange einige MIME-Typ - überhaupt! - der Sie zugeordnet ist.Wenn ich zum Beispiel geben Sie einfach einen URL in die Adresse-Leiste in Chrom oder Firefox, die
Accept
- header der browser sendet, ist im Falle von Chrom...... und im Falle von Firefox:
Beide Header enthalten
*/*
als einen akzeptablen Inhaltstyp, und erlauben somit den server zu dienen, eine Datei von beliebiger content-Typ es mag. Aber einige weniger gängigen Browsern nicht akzeptieren*/*
- oder vielleicht es zählen nur für die Seite Anfragen, nicht beim laden den Inhalt einer<script>
oder<img>
- tag, Sie könnte auch dienen, durch das PHP - und das ist unser problem kommt.Wenn man sich mal die user-agents der requests, führen 406 Fehler, werden Sie wahrscheinlich sehen, dass Sie aus relativ ungewöhnliche user-agents. Wenn erlebte ich diesen Fehler, es war, als hatte ich den
src
einer<img>
element verweist auf ein PHP-Skript, dass dynamische Bilder (mit der.php
Erweiterung in der URL nicht auftauchen), und ich zum ersten mal erlebt, es andernfalls für BlackBerry-Nutzer:Um dies zu umgehen, benötigen wir lassen
mod_negotiate
dienen PHP-Skripte über einige andere Mittel, als Ihnen eines beliebigen Typs, und dann unter Berufung auf den browser zu senden eineAccept: */*
header. Um dies zu tun, verwenden wir dieMultiviewsMatch
Richtlinie, um festzulegen, dass multiviews dienen kann, PHP-Dateien, unabhängig davon, ob Sie übereinstimmen, wird die AnfrageAccept
header. Die Standard-option istNegotiatedOnly
:Aber wir können bekommen, was wir wollen, mit der
Any
option:Beschränken, diese Regel zu ändern nur um
.php
Dateien, verwenden wir eine<Files>
Richtlinie, wie diese:Und mit einem winzigen (aber schwierig-zu-Bild-out) ändern, sind wir fertig!
Die Antwort von Mark Amery ist fast komplett, jedoch fehlt es den sweet spot und nicht auf die 'keine Erweiterung ist in der Anfrage so Aushandlung schlägt fehl mit alternativen.
Können Sie diesen Fehler beheben, indem die folgende config-Schnipsel:
Ihre PHP-Konfiguration sollte so etwas wie dieses:
NICHT verwenden
AddType application/x-httpd-php .php
oder andere AddTypeUnd Ihre zusätzlichen Konfig sollte wie folgt sein:
Wenn Sie verwenden AddType erhalten Sie Fehler wie diese:
Wie Sie sehen können, es nicht finden index.php jedoch bedeutet es nicht, verwenden Sie diese alternative, denn es kann nicht übereinstimmen, die
Accept: image/*
zuapplication/x-httpd-php
. Wenn Sie eine Anfrage/index.php/1/2/3/4
es funktioniert gut.Den Grund dafür fand ich in den source code von dem Modul mod_negotiation. Ich habe versucht, herauszufinden, warum der Apache funktionieren würde, wenn die .php-Typ war 'cgi', aber nicht (Hinweis:
application/x-httpd-cgi
ist hardcoded..). Während in der Quelle, die ich bemerkt, dass der apache nur die Datei als eine übereinstimmung, wenn der Content-Type der Datei entsprach dem Accept-header, oder wenn der Content-Type der Datei war leer.Wenn Sie mit der SetHandler als apache nicht sehen .php-Dateien als
application/x-httpd-php
, aber leider, viele distro ' s auch definieren, diese in die /etc/mime.Typen-Datei. Also, um sicher zu sein, fügen Sie einfach dieRemoveType .php
zu deiner config, wenn dieser bug stört Sie.