Tutorial zur Verarbeitung statischer Ressourcen in Tomcat

Tutorial zur Verarbeitung statischer Ressourcen in Tomcat

Vorwort

Alle Anfragen in Tomcat werden von Servlet verarbeitet, und statische Ressourcen sind keine Ausnahme. In der Standarddatei web.xml ist ein DefaultServlet zur Verarbeitung statischer Ressourcen konfiguriert, das die Zwischenspeicherung und Wiederaufnahme von Haltepunkten unterstützt.

Die grundlegende Verarbeitung von DefaultServlet ist wie folgt:

  • Überprüfen, ob eine Ressource zwischengespeichert ist
  • Überprüft, ob die im optionalen If-Headerfeld angegebene Bedingung erfüllt ist.
  • Setzen Sie Antwortheaderfelder wie Content-Type, Content-Length, ETag, Last-Modified
  • Überprüft, ob die Bedingungen von Sendfile erfüllt sind, andernfalls kopiert er den Inhalt in den Ausgabestream

Als nächstes werden wir hauptsächlich das Design und die Implementierung des Ressourcen-Cachings sowie die Verarbeitung des If-Headerfelds analysieren.

1. Ressourcen-Cache-Design

Da die Zugriffsgeschwindigkeit auf die Festplatte wesentlich geringer ist als die Zugriffsgeschwindigkeit auf den Arbeitsspeicher, kann das ordnungsgemäße Zwischenspeichern einiger statischer Ressourcen zu schnelleren Systemreaktionen führen.

Als Tomcat die Verarbeitung statischer Ressourcen in Version 6.0.53 implementierte, verwendete es einige JNDI-APIs (aber es schien, dass dies bei der Verwendung wenig mit JNDI zu tun hatte). Die relevanten Klassendiagramme und Kernmethoden und -eigenschaften lauten wie folgt:

Cache-bezogene Klassen:

  • ResourceCache: Cache-Implementierung, die Funktionen zum Suchen, Laden und Löschen von Ressourcen bereitstellt
  • CacheEntry: Ein Cache-Eintrag, einschließlich des Cache-Namens, z. B. /tomcat.gif, der Ressource und der Ressourcenattribute sowie des entsprechenden Verzeichnisses

Die mit dem Ressourcenverzeichnis in Zusammenhang stehenden Klassen sind:

  • EmptyDirContext: Wird hauptsächlich im eingebetteten Modus verwendet und verhält sich, als ob keine Ressourcen verfügbar wären
  • FileDirContext: Dateisystembasierter Ressourcenverzeichnisdienst
  • WARDirContext: Verzeichnisdienst basierend auf War-Datei
  • Ressource: kapselt Ressourceninhalte, hauptsächlich Bytedaten und Eingabestream
  • ResourceAttributes: Ressourcenattribute, hauptsächlich Inhaltslänge und letzte Änderungszeit
  • ProxyDirContext: Ein Proxy für Ressourcen-Cache und Verzeichnisdienste, der Funktionen wie das Suchen des Ressourcen-Cache und die Überprüfung, ob der Cache abgelaufen ist, bereitstellt.

Standardmäßig beträgt die maximale Cachegröße 10 MB, die maximale Größe einer einzelnen zwischengespeicherten Ressource beträgt 512 KB und die Cache-TTL beträgt 5 Sekunden.

Wenn ein Mapper einem Wrapper zugeordnet wird, der statische Ressourcen verarbeitet, führt dies im Allgemeinen zum Laden von Ressourcen. Die grundlegenden Methodenaufrufe lauten wie folgt:

Mapper.map(MessageBytes, MessageBytes, MappingData)
└─Mapper.internalMap(CharChunk, CharChunk, MappingData)
 └─Mapper.internalMapWrapper(Mapper$Context, CharChunk, MappingData)
 └─ProxyDirContext.lookup(Zeichenfolge)
 └─ProxyDirContext.cacheLookup(Zeichenfolge)
 └─ResourceCache.lookup(Zeichenfolge)
  └─ResourceCache.find(CacheEntry[], String)

Cache-Ressourcen werden der Reihe nach in das interne Array eingefügt. Die Find-Methode führt eine binäre Suche im Cache nach Ressourcennamen durch, wobei der Ressourcenname der Anforderungspfad ist. Es gibt zwei Situationen: Cache-Treffer und Cache-Fehlschlag.

Wenn der Cache fehlt, wird in der Methode cacheLookup ein neues CacheEntry-Objekt erstellt und die Methode cacheLoad aufgerufen, um es dem Cache-Array von ResourceCache hinzuzufügen. Vor dem Hinzufügen werden die folgenden Vorgänge für den Cache-Eintrag ausgeführt:

  • Abrufen und Initialisieren der Cache-Ressourceneigenschaften, hauptsächlich contentLength und lastModified der Datei
  • Wenn die Dateilänge weniger als 512 KB beträgt, laden Sie den Dateiinhalt in den Speicher
  • Markieren Sie den Cache als vorhanden und legen Sie den Cache-Zeitstempel fest

Cache-Treffer verifizieren den Cache-Eintrag:

  • Überprüfen Sie, ob es abgelaufen ist und die aktuelle Zeit größer ist als der für den Cache-Eintrag festgelegte Zeitstempel
  • Wenn es abgelaufen ist, prüfen Sie, ob der Ressourceninhalt geändert wurde
  • Wenn geändert, diesen Cache leeren und den neuesten Inhalt lesen

Das Obige ist ein einfacher Verarbeitungsprozess der Ressourcen-Zwischenspeicherung.

2. Verarbeitung des If-Headerfeldes

Der Client empfängt und speichert die angeforderte Ressource im Cache. Wenn die Ressource erneut angefordert wird, überprüft der Server anhand des spezifischen Anforderungsheaderfelds, ob die Ressource geändert wurde. Wenn keine Änderung vorliegt, wird nur die Antwort „304 Not Modified“ zurückgegeben. Andernfalls wird der Inhalt der Ressource zurückgegeben, wodurch Bandbreite gespart wird.

Zur Ressourcenüberprüfung werden zwei Headerfelder verwendet: Last-Modified+If-Modified-Since und ETag+If-None-Match.

Last-Modified+If-Modified-Since, die Einheit ist Sekunden. Das ist leicht zu verstehen. Wenn die letzte Änderungszeit der Serverressource kleiner als der Wert von If-Modified-Since ist, bedeutet dies, dass sich die Ressource nicht geändert hat. If-Modified-Since entspricht If-Unmodified-Since, was einer Assertion ähnelt. Es werden nur Ressourcen mit einem Zeitstempel zurückgegeben, der kleiner als dieser ist. Wenn der Zeitstempel größer oder gleich diesem ist, wird ein Fehler 412 Precondition Failed zurückgegeben.

Die Verwendung der Zeitstempelvalidierung bringt mehrere Nachteile mit sich:

  • Die Datei kann nur den Änderungszeitpunkt ändern, der Inhalt bleibt jedoch unverändert
  • Dateien, die in weniger als einer Sekunde geändert wurden, können nicht beurteilt werden
  • Der Server kann den letzten Änderungszeitpunkt der Datei möglicherweise nicht genau ermitteln.

Aus diesem Grund hat HTTP ETag eingeführt. ETag (Entity Tags) ist eine eindeutige Kennung für eine Ressource, die als vom Server für die Ressource generiertes Token betrachtet und verwendet werden kann, um zu überprüfen, ob die Ressource geändert wurde. HTTP legt nur fest, dass ETag in Anführungszeichen gesetzt werden soll, schreibt aber nicht vor, was der Inhalt ist oder wie er implementiert werden soll. Tomcats Logik zum Generieren von ETag ist "W/\"" + contentLength + "-" + lastModified + "\"" , wobei "W/" Groß- und Kleinschreibung angibt.

ETag+If-None-Match. Der Wert von If-None-Match besteht aus einem oder mehreren durch Kommas getrennten ETags. Wenn der ETag der Serverressource keinem davon entspricht, bedeutet dies, dass die angeforderte Ressource geändert wurde; andernfalls gibt es keine Änderung. Es hat auch einen speziellen Wert – ein Sternchen (*), das nur beim Hochladen von Ressourcen verwendet wird, normalerweise bei der PUT-Methode, um zu überprüfen, ob sie hochgeladen wurden.

Darüber hinaus hat If-None-Match eine höhere Priorität als If-Modified-Since, d. h. wenn If-None-Match vorliegt, wird der letzte Änderungszeitpunkt nicht geprüft. Das Gegenteil von If-None-Match ist If-Match, das ebenfalls einer Assertion ähnelt. Es gilt nur dann als unverändert, wenn das ETag der Ressource übereinstimmt. Es wird normalerweise zum Fortsetzen von Haltepunkten verwendet.

Der Kerncode von Tomcat zur Implementierung dieses Teils lautet wie folgt:

//Gibt nur dann „true“ zurück, wenn die Ressource als geändert gilt protected boolean checkIfHeaders(HttpServletRequest request,
  HttpServletResponse-Antwort, ResourceAttributes resourceAttributes)
  wirft IOException {
 returniere checkIfMatch(Anfrage, Antwort, Ressourcenattribute)
  && checkIfModifiedSince(Anfrage, Antwort, Ressourcenattribute)
  && checkIfNoneMatch(Anfrage, Antwort, Ressourcenattribute)
  && checkIfUnmodifiedSince(Anfrage, Antwort, Ressourcenattribute);
}

2.1 Einmaliger Antragsprozess

Am Beispiel der Anforderung für die statische Ressource /main.css lauten die Header-Informationen der ersten Anforderungsantwort wie folgt:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Akzeptierte Bereiche: Bytes
ETag: W/"72259-1557127244000"
Letzte Änderung: Montag, 6. Mai 2019, 7:20:44 Uhr GMT
Inhaltstyp: Text/CSS
Inhaltslänge: 72259
Datum: Montag, 6. Mai 2019, 07:20:57 GMT

Wenn Sie die zweite Anfrage stellen, sehen Sie sich zunächst die Schlüsselinformationen im Header-Feld der Anfrage an:

Cache-Steuerung:max-age=0
Verbindung: Keep-Alive
Gastgeber:localhost:8080
Wenn geändert seit: Montag, 6. Mai 2019, 07:20:44 GMT
Wenn keine Übereinstimmung: Mit „72259-1557127244000“

Nach Erhalt der Anfrage vergleicht der Server das ETag. Wenn die Übereinstimmung erfolgreich ist, bedeutet dies, dass die Ressource nicht geändert wurde. Die Antwort lautet wie folgt:

HTTP/1.1 304 Nicht geändert
Server: Apache-Coyote/1.1
ETag: W/"72259-1557127244000"
Datum: Montag, 6. Mai 2019, 07:21:46 GMT

Hinweis: Verwenden Sie beim Reproduzieren den Texttyp. Wenn Sie den Chrome-Browser verwenden, denken Sie daran, den Cache zu aktivieren.

2.2 Akzeptanzbereiche

In der obigen Antwort setzt der Server einen Accept-Ranges: bytes-Header, was wörtlich bedeutet, dass ein Teil der Bytes der Ressource angefordert werden kann. Wenn der Client diesen Header findet, kann er versuchen, die Übertragung fortzusetzen.

Der Parsing-Prozess ist die Implementierung der HTTP-Spezifikation. Wir werden ihn hier nicht im Detail analysieren. Detaillierte Informationen zur Spezifikation finden Sie in RFC7233#section-2.3.

3. SendFile-Verarbeitung

Überprüfen Sie, ob SendFile unterstützt wird. Dieser Vorgang wird im NIO-Modus unterstützt, d. h. Zero Copy. Dieser Vorgang reduziert eine Kopie in den Anwendungsspeicher und schreibt Daten direkt vom Kernel in den Kanal. Tomcat versucht, mit dieser Methode Dateien zu senden, die größer als 48 KB sind.

4. Zusammenfassung

Die Implementierung der Verarbeitung statischer Ressourcen durch Tomcat ist relativ vollständig, steht jedoch Webservern wie Nginx immer noch etwas nach, da diese statische Ressourcen direkt verarbeiten können, während Tomcat eine zusätzliche Zuordnung vornehmen muss. Im Allgemeinen wird eine dynamische und statische Trennung vorgenommen, damit sich Tomcat auf die Verarbeitung dynamischer Anforderungen konzentrieren kann.

Zusammenfassen

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • Lösung für Tomcats Fehler beim Laden statischer Ressourcendateien wie CSS und JS
  • Detaillierte Erläuterung von Nginx + Tomcat zum Trennen von Anforderungen für dynamische Daten und statische Ressourcen

<<:  Installationstutorial für MySQL 5.1 und 5.7 unter Linux

>>:  Detaillierte Erklärung der Hook-Funktion und -Nutzung im Lebenszyklus der neuen Version von React

Artikel empfehlen

So lösen Sie das Problem des verstümmelten DOS-Fensters in MySQL

Das Problem mit dem verstümmelten Code ist folgen...

Analyse des Uniapp-Einsteiger-NVUE-Klettergrubenrekords

Inhaltsverzeichnis Vorwort Hallo Welt Bild Rahmen...

Analyse des Ereignisschleifenmechanismus von js

Vorwort Wie wir alle wissen, ist JavaScript im Ke...

So passen Sie einen EventEmitter in node.js an

Inhaltsverzeichnis Vorwort 1. Was ist 2. So verwe...

Es ist ganz einfach zu verstehen, was Node.js ist

Inhaltsverzeichnis Offizielle Einführung in Node....

Grafisches Tutorial zur Installation und Konfiguration von MySQL 8.0.15 winx64

In diesem Artikel wird die Installations- und Kon...

Tutorial zur Migration von MySQL von phpstudy nach Linux

Projektzweck Migrieren Sie die Daten in MySQL 5.5...

Beispiel für die Implementierung von Unterstreichungseffekten mit CSS und JS

In diesem Artikel werden hauptsächlich zwei Arten...

Rückblick auf die besten Webdesign-Arbeiten 2012 [Teil 1]

Zum Beginn des neuen Jahres möchte ich meinen Fre...

Docker-Image-Optimierung (von 1,16 GB auf 22,4 MB)

Inhaltsverzeichnis Der erste Schritt der Optimier...

JavaScript navigator.userAgent erhält Browserinformationen – Fallerklärung

Der Browser ist für uns wahrscheinlich das vertra...