Sven Rautenberg: Browser-Identifikation auch bei Opera - ABER WIE ???

Beitrag lesen

Erstmal: Wozu muss der Browser identifiziert werden? Es ist in 90% der Fälle nicht sinnvoll, die Angabe "User-Agent" auszuwerten, denn die hat viel zuviele Varianten, die gar nicht alle abzudecken sind.

Außer der Variante "ich verkaufe den Macher einer Seite für dumm und behaupte, mein Browser sei XY" wüsste ich jetzt keine.

Ähm, du weißt, wie viele Browser es auf der Welt gibt? Wieviele verschiedene User-Agent-Strings es gibt?

Mein Kernpunkt ist: Browsererkennung, die gerne in Browserweichen mündet, um je nach Browser gewisse Javascriptteile auszuführen, sollten sich ausschließlich anhand der vorhandenen DOM-Objekte orientieren, nicht an irgendwelchen User-Agent-Angaben.

Der klassische Reinfall: Mit der Veröffentlichung von Netscape 6.0 funktionierten nicht nur viele Webseiten nicht, sondern produzierten Javascriptfehler in Massen. Grund: Es wurde anhand des User-Agent-Strings entschieden: Ist "MSIE" enthalten, dann nimm document.all, und ansonsten document.layers.

Das klappt natürlich nicht, wie wir alle wissen. Besser wäre: Wenn document.all existiert, dann nimm das. Wenn document.layers existiert, dann nimm das. Dadurch würde die Webseite zwar noch nicht funktionieren, aber die Fehler wären schon mal weg - und außerdem läßt sich solch ein Konstrukt eben relativ leicht um "Wenn document.getElementById, dann nimm dieses" erweitern.

Würden alle Browser mit den W3C-Normen perfekt klar kommen, würde diese Problematik für mich nicht existieren. Fakt ist aber, dass selbst Gecko unter anderem CSS2 noch nicht vollständig implementiert hat, von XHTML1.1 Ruby noch nicht kann, von HTML 2.0 <link> in neueren Builds aus Performance-Gründen nicht sinnvoll auswertet, uswusf. Ganz zu schweigen von IE, der noch nicht mal ansatzweise an diese Qualität herankommt.

Ja, und? Das sind alles Dinge, die in Supersonderfällen vielleicht mal interessant sind. Also für Bastler. Sie verbieten sich von selbst, wenn man kommerzielle Webseiten produzieren will, die auf einer breiten Browserbasis funktionieren müssen.

Man kann das bedauern - aber es ist eben auch Fakt, dass gewisse Webseiten sich eher am kleinsten gemeinsamen Nenner orientieren müssen. Dabei sind die Möglichkeiten der Gestaltung schon recht groß, wenn man Netscape 4 einfach außer acht läßt. Und auch dieser Browser kann mit abgespeckten CSS-Dateien zur Mitarbeit überredet werden.

Eine umfangreichere Site mit komplexen Layout (so etwas wird mir nunmal vorgegeben) kann ich daher nur realisieren, wenn ich den UA-String auswerte. Server-seitig, über Perl oder PHP; nicht client-seitig mittels JavaScript.

Das kannst du natürlich machen - die Frage ist: Was passiert, wenn dir unbekannte Browser die Site besuchen? Kriegen die dann die volle Feature-Ladung geboten, oder bist du arg konservativ und lieferst HTML 2.0 aus (um es mal extrem auszudrücken ;) )? Was ist, wenn der unbekannte Browser alles komplett beherrschen würde, was du brauchst, es aber nicht kriegt?

Ich halte das Auswerten des User-Agent-Strings _serverseitig_ für groben Unfug - diese Angabe kann viel zu leicht verändert werden oder ungewollt verlorengehen (ja, manche uneinsichtige Admins filtern die Angabe aus Sicherheitsgründen am Firmenproxy heraus - was dann?). Auch clientseitig ist es nicht viel besser - wegen der gleichen Problematik. Allerdings ist es unwahrscheinlicher, gar keine Angabe zu erhalten, aber genauso wahrscheinlich, unerwartete Angaben zu erhalten.

Was Sinn macht, ist die Auswertung, ob der Browser document.getElementById (alle neuen), document.all (IE4) oder document.layers (NS4) kennt - sofern man diese Methoden in seinem Skript verwenden will.

Leider nein. Abgesehen davon, dass derartiges server-seitig nicht auswertbar ist (was nötig ist, um jede menge Traffic zu sparen - oder soll ich z.B. Stylesheets übertragen, aber die letztlich nicht vom Browser benutzen lassen?), ist diese Methode allmählich auch veraltet, denn

  • Opera kann inzwischen leider teilweise document.all

Nur, wenn er als Internet Explorer getarnt ist.

  • bei Mozilla bahnt sich leider, leider eine document.all-Implementation an, und evtl. auch eine document.layers-Implementation. Natürlich versuchen viele, das zu verhindern.

Ist auch unproblematisch, siehe unten...

  • afaik kann auch Konqueror teilweise document.all

Dito.

  • mit "alle neuen" weisst du nicht, ob es IE 5 oder IE 6 ist. Ersterer hat bekanntlich große box-model-Macken.

Auch dagegen ist ein Kraut gewachsen.

Die Javascript-Lösung ist eigentlich ganz einfach.

Ausgangspunkt: Die primär zu benutzende Lösung ist das W3C-DOM. Das können alle neuen Browser mehr oder weniger (die derzeit bestehenden Einschränkungen des Opera-Browsers, gewisse Inhalte und CSS-Werte nachträglich zu verändern, sind bekannt - sowas macht man dann einfach nicht ;) ).

Wenn document.getElementById nicht vorhanden ist, wird als Ausweichlösung mit document.all gearbeitet (das sollte im Prinzip nur für IE 4 zutreffen). Wenn das nicht vorhanden ist, wird mit document.layers gearbeitet (was nur für den NS 4 zutrifft).

Wenn neue Browser auftauchen, dann werden die hoffentlich das W3C-DOM verstehen und durch diese Abfrage ganz automatisch mit berücksichtigt. Und auch wenn sie stattdessen eines der alternativen DOM-Modelle kennen, werden sie immer noch berücksichtigt (wenngleich die Wahrscheinlichkeit dafür gegen Null geht).

Was den Traffic angeht: Nach meinen Erfahrungen blähen sich lediglich die Javascript-Dateien ein wenig auf. Und ggf. laden die besseren Browser (also alles außer Netscape 4) zwei statt nur einer CSS-Datei, damit dieses alte, aber verbreitete Modell zumindest etwas anzeigt, die anderen Browser aber bessere grafische Darstellungen bringen können.

Und server-seitig sollte man den UA-String ohnehin nicht auswerten. Was ein Browser macht und kann, dass weiß der Browser selbst am besten. Es ist Aufgabe des Programmierers, für die häufigsten Browser funktionierende Lösungen zu erstellen - und dabei keinesfalls andere, unberücksichtigte Browser auszuschließen. Er soll sich an die W3C-Standards halten. Die Browser werden dies auch tun - und schon funktioniert die Seite.

Wer seinen UA-String abfälscht, ist letztlich selbst schuld: trifft man auf eine Site, die kategorisch nach UA-String den Browser, den man benutzt, aussperrt, so sollte man diese nach Möglichkeit demonstrativ links liegen lassen. Ist das nicht möglich, so kann man von mir aus für diese Site den UA-String kurzzeitig umstellen, sollte das aber keineswegs dauerhaft tun.

Wer für die Fälschung des UA-Strings nichts kann, hat der dann Pech gehabt? Er erhält ja schlimmstenfalls keinerlei Hinweis darauf, was sein Browser falsch macht. Er sieht nur eine kaum existente, unbenutzbare oder grausam designte Seite. Und mit welcher Angabe hätte er denn mehr Erfolg? Weiß er, wie er diesen UA-String setzen kann? Was ist, wenn er einen W3C-DOM-Browser hat, sich aber als IE ausgibt - und dann mit document.all beworfen wird?

Ferner gibt es solche, die das aus Spaß machen, mit UA-Strings wie "Kitchen/1.0 (modern)" etc. - damit ist der Sinn des Headers ad absudrum geführt, und da gilt wirklich "selbst schuld".

Selbst schuld ist der Programmierer der Seite, der nicht begriffen hat, dass die UA-Angabe infomativen Charakter hat, aber keinesfalls genormt ist oder in irgendeiner Weise verläßlich ist. Die Angabe des UA-Strings ist optional!

Und das steht unter anderem auch in der RFC 2616 (HTTP/1.1) im Kapitel 12.1.

<quote>
12.1 Server-driven Negotiation

If the selection of the best representation for a response is made by an algorithm located at the server, it is called server-driven negotiation. [...]

Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent, or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user). In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.

Server-driven negotiation has disadvantages:

1. It is impossible for the server to accurately determine what might be "best" for any given user, since that would require complete knowledge of both the capabilities of the user agent and the intended use for the response (e.g., does the user want to view it on screen or print it on paper?).

2. Having the user agent describe its capabilities in every request can be both very inefficient (given that only a small percentage of responses have multiple representations) and a potential violation of the user's privacy.

3. It complicates the implementation of an origin server and the algorithms for generating responses to a request.

4. It may limit a public cache's ability to use the same response for multiple user's requests.
</quote>

Dem ist IMO nichts mehr hinzuzufügen.

- Sven Rautenberg