Blog ·
Ein Abzeichen, das Cookies setzte
Ein Bild in der Fußzeile kostete auf der ganzen Site zweiundzwanzig Lighthouse-Punkte. Die Abhilfe war nicht, es zu entfernen, sondern was ein Proxy verweigert.
Von Provibr
Der Best-Practices-Wert unserer Marketingsite lag auf jeder Seite bei 78. Nicht auf einer Seite, auf jeder: der Startseite, der Preisseite, der Dokumentation, allem, gleichmäßig. Gleichmäßige Werte sind ein gutes Zeichen, denn sie bedeuten, dass die Ursache in etwas liegt, das jede Seite teilt.
Es war ein Bild-Tag in der Fußzeile. Ein Abzeichen eines Starteintrags, direkt von der Plattform geladen, die es ausgibt, denn so soll ein solches Abzeichen eingebunden werden und weil die Zahl darauf live sein soll.
Was ein Bild-Tag anrichten kann
Das Abzeichen wird von einem API-Host ausgeliefert, der hinter Cloudflare sitzt, und Cloudflare beantwortet Anfragen mit seinem Bot-Management-Cookie: __cf_bm, SameSite=None, Secure, gebunden an die Domain des Ausgebers. Das ist keine Entscheidung der Site, deren Abzeichen es ist. Es ist, was ein CDN tut, auf einem SVG, bei jedem Seitenaufruf, für jeden Besucher.
Zwei Lighthouse-Prüfungen reagieren darauf. Die Prüfung auf Cookies von Dritten wiegt fünf der achtundzwanzig Gewichte der Kategorie, und ein Inspektorbefund wiegt eins. Sechs Gewichte, verloren an ein Bild. Über die achtunddreißig Messungen der vorigen Runde war das der gesamte Abstand zwischen 78 und 100.
Die dritte Folge ist die, die kein Wert erfasst. Die IP-Adresse jedes Besuchers ging an ein Unternehmen, mit dem zu sprechen er nicht gewählt hatte, auf jeder Seite, im Tausch gegen eine Zahl in einer Fußzeile.
Es zu entfernen ist auch nicht die Antwort
Wir hatten die Abwägung schon Monate zuvor in einem Kommentar aufgeschrieben: wenn Sie das je ohne Einwilligungsbanner wollen, ist das SVG selbst zu hosten der Weg. Mit dem Gegenargument daneben, dass eine selbst gehostete Kopie eine Fotografie ist. Das Abzeichen gibt es, um einen lebenden Eintrag zu zeigen; frieren Sie die Bytes ein, und Sie haben ein Bild eines Eintrags.
Es gibt einen dritten Weg, und er wird erst offensichtlich, wenn man zwei Dinge trennt, die ein Browser gleichzeitig tut. Der Browser holt Bytes, und der Browser baut eine Verbindung auf. Nur das Zweite ist das Problem.
Das Abzeichen kommt also jetzt von unserem eigenen Ursprung, über einen Pfad unserer eigenen API, und diese Route holt die Gegenstelle auf dem Server. Dieselben Bytes. Der Browser des Besuchers stellt eine Anfrage, an uns. Es gibt auf der Leitung nichts, worauf sich ein Cookie setzen ließe, denn in der Seite des Besuchers steckt überhaupt kein Dritter. Und die Zahl bleibt live, denn wir fragen weiterhin nach.
Best Practices ging bei zweiunddreißig von sechsunddreißig Messungen von 78 auf 100. Die restlichen vier sind die Artikelseiten, die wegen einer ganz anderen Schaltfläche eines Dritten bei 96 liegen, und das ist eine eigene Entscheidung und kein Rest.
Was ein Proxy dem schuldet, für den er vermittelt
Fremde Bytes vom eigenen Ursprung auszuliefern ändert, was sie sind. Ein SVG, das über ein Bild-Tag geladen wird, kann kein Skript ausführen; das ist eine Zusicherung der Spezifikation, und eine gute. Aber in dem Moment, in dem diese Bytes von unserer Domain kommen, gehört uns, was darin steht.
Die Route prüft die Antwort also, bevor sie sie weitergibt. Diese Prüfung ist mit Absicht kein Bereiniger. Ein Bereiniger versucht, gefährlichen Inhalt sicher zu machen; diese hier verweigert alles, was nicht wie das Abzeichen aussieht, das wir schon kennen, und die Route fällt auf eine eingefrorene Kopie zurück. Der schlimmste Fall ist ein Abzeichen von heute Morgen statt eines Abzeichens von dieser Minute, und das ist ein Preis, den es wert ist, nie darüber nachdenken zu müssen, was in der Antwort eines anderen stecken könnte.
Zwei der Verweigerungen zielen genau auf das, wofür diese ganze Änderung da war. Ein SVG kann ein externes Bild referenzieren, und es kann aus einer Stildeklaration heraus eine externe Ressource referenzieren. Beides würde eine Schicht tiefer als das gerade entfernte Tag nach einem Dritten greifen, aus einer Datei heraus, die wir als unsere eigene ausliefern. Eine Prüfung, die nur nach Skripten sucht, hätte beide durchgelassen.
Mit Absicht auf ein Bild zurückfallen
Jeder Fehlerpfad gibt die eingefrorene Kopie mit Status 200 zurück. Netzwerkfehler, Zeitüberschreitung, ein Status, der nicht 200 ist, ein Rumpf, dem die Prüfung nicht traut: alle, 200, mit einem Abzeichen darin.
Die Begründung hat damit zu tun, wie das Scheitern aussieht. Eine 404 oder eine 502 auf einem Bild in der Fußzeile jeder Seite ist auf jeder Seite ein Symbol für ein kaputtes Bild, das sich als kaputte Site liest, für ein schmückendes Element. Ein etwas altes Abzeichen liest sich als gar nichts.
Der Ausgleich ist, dass der Fehlerpfad eine kurze Cache-Kopfzeile trägt und der Erfolgspfad eine lange. Sonst würde ein fünfminütiger Ausfall bei der Gegenstelle die eingefrorene Kopie für das volle Cache-Fenster vor allen festnageln.
Es gibt eine eingefrorene Kopie, und sie liegt mit Absicht nicht als Datei im öffentlichen Verzeichnis. Als Datei hätte sie neben der Route eine zweite öffentliche Adresse, und eine künftige Runde könnte mit guten Gründen ein Bild-Tag setzen, das direkt darauf zeigt, was still das lebende Verhalten entfernt, zu dessen Erhalt diese ganze Anordnung besteht. Als Konstante gehalten, führt der einzige Weg, sie auszuliefern, über die Route, die es auch erst im Netz versucht.
Zwei Caches mit verschiedenen Aufgaben
Es gibt hier zwei Cache-Schichten, und sie zu verwechseln erzeugt ein System, das entweder auf die Gegenstelle einhämmert oder für immer alte Bytes zeigt.
Der Datencache des Frameworks hält die Antwort der Gegenstelle: bei sechs Stunden Neuvalidierung löst ein Besucher alle sechs Stunden eine ausgehende Anfrage aus, unabhängig vom Verkehr. Die HTTP-Cache-Kopfzeile hält unsere Antwort, am CDN und im Browser. Die Gegenstelle setzt auf ihrer eigenen Antwort vier Stunden; sechs auf unserer Seite sind ein bewusster halber Schritt mehr, damit ein Ausfall drüben uns nicht im Vierstundenrhythmus auf die eingefrorene Kopie fallen lässt.
Eine kleine Falle, die einen Build gekostet hat. Next liest die Konfiguration eines Routensegments statisch aus der Quelle, der Export für die Neuvalidierung muss also eine wörtliche Zahl sein. Ihn als Ausdruck zu schreiben, selbst als Konstante, die ein paar Zeilen tiefer in derselben Datei deklariert wird, bricht den Build mit einem Fehler über eine ungültige Segmentkonfiguration ab. Die Konstante liest jetzt aus dem Export statt umgekehrt, es gibt also weiterhin genau eine Zahl.
Die 307, die eine Startoption war
Dieselbe Runde hat Zeit auf etwas verwendet, das wie ein Routingfehler aussah und keiner war, und es ist festhaltenswert, weil es eine frühere Runde vollständig verbraucht hat.
Wenn man den Produktionsbuild lokal laufen ließ, antwortete jeder nackte Marketingpfad mit 307 und leitete auf sich selbst um. Nicht die lokalisierten Pfade, nicht die API-Routen: die nackten. Das hatte die englische Hälfte jedes lokalen Layoutdurchlaufs wochenlang blockiert und war als unerklärter Defekt notiert worden.
Es ist die Hostbindung. Mit einer wörtlichen Loopback-Adresse als Hostnamen gestartet, lässt Next diesen Wert stehen, während ein leerer Hostname oder ein Platzhalter auf localhost normalisiert wird. Die anfängliche URL und der Ursprung, den die Middleware berechnet, gehen dann auseinander, das Umschreiben bleibt absolut, der Router hält es für extern und läuft erneut hinein. Mit dem Platzhalter gestartet, dem Wert, den die Produktion benutzt, oder mit localhost, antwortet alles mit 200.
Es gab nichts zu reparieren. Zu tun war, die richtige Startzeile in das Skript zu schreiben und aufzuschreiben warum, denn ein Defekt, der in Wahrheit eine Option ist, wird sonst von der nächsten Person mit derselben Zuversicht wiederentdeckt.
Das Scheitern, das wir nicht behoben haben
Ein drittes Ding aus derselben Runde ist eine bewusste Nichtreparatur, und die verdienen es, mindestens so sorgfältig aufgeschrieben zu werden wie Abhilfen.
Wir hatten im Feld 404er auf Chunks gesehen: HTML, das JavaScript-Dateien referenziert, die es nicht mehr gibt. Die Erklärung war am Ende eine einzige Kopfzeile. Die Startseite trägt ein stale-while-revalidate-Fenster von einem Jahr, ein CDN-Rand darf also sehr lange HTML aus einem älteren Build ausliefern, und die Chunknamen in diesem HTML gehören zu diesem Build.
Der Regler liegt direkt daneben, und wir haben ihn in Ruhe gelassen, denn genau diese alte Kopie hat die Site zwei Wochen zuvor während einer Absturzschleife der Datenbank am Antworten gehalten. Das Fenster zu verkürzen tauscht einen seltenen kaputten Aufruf gegen einen noch selteneren Totalausfall. Das ist eine echte Abwägung, sie gehört dem, der das Risiko trägt, und die Aufgabe der Runde war es, den Mechanismus zu erklären, und nicht, zu entscheiden.
Was wir aufschreiben würden
- Ein gleichmäßiger Wert auf jeder Seite zeigt auf etwas, das jede Seite teilt. Das ist die billigste Spur, die Sie bekommen.
- Ein Bild-Tag ist eine Verbindung und nicht nur Bytes. Alles, was ein CDN bei einer Anfrage tun will, tut es auch bei dieser.
- Selbst hosten ist nicht die einzige Alternative zum Einbinden. Auf dem Server zu holen bewahrt das lebende Verhalten und nimmt den Dritten aus der Seite des Besuchers.
- Sobald Sie fremde Bytes ausliefern, sind es Ihre. Prüfen Sie sie, und prüfen Sie gezielt auf die Verweise, die das gerade geschlossene Loch wieder öffnen würden.
- Ein altes Bild ist besser als ein kaputtes. Bei Schmuck kostet ein sichtbares Scheitern mehr als ein unsichtbares Veralten, solange das Altersfenster auf dem Fehlerpfad kurz ist.
- Geben Sie der eingefrorenen Kopie keine öffentliche Adresse. Was erreichbar ist, wird irgendwann verlinkt, und der lebende Pfad wird still umgangen.
- Wissen Sie, welcher Cache was hält. Einer hält die Antwort der Gegenstelle, einer Ihre, und ihre Fenster beantworten verschiedene Fragen.
- Manches Rot ist eine Option und kein Fehler. Bilden Sie den Mechanismus nach, bevor Sie das Symptom reparieren, und wenn es Ihr eigener Startbefehl war, sagen Sie es im Skript.
Zur Klarheit: die Route ist live, und die Werte stammen aus einem lokalen Produktionsbuild über sechsunddreißig Messungen, nicht aus Felddaten. Die Erklärung für die 404er auf Chunks ist aus Kopfzeilen abgeleitet und wurde nicht nachgestellt, und die Entscheidung über dieses Cache-Fenster gehört der Person, die das Verfügbarkeitsrisiko trägt, und nicht der Runde.
Aus der Plattformarbeit an Provibr. Eine weitere Messung, die aus dem falschen Grund grün war, steht in Barrierefreiheit: eine Ausnahme, die sich misst, und ein Feld, das eine Absicht hielt, wo eine Tatsache hingehörte, steht in ein Datum in der Zukunft ist kein Plan.