Einführung
Die Veranstaltung Garden Night hat mehrere lokale Webzugänge: Anmeldung, Lageplan, Personalseite und Ticketinformationen. Vor der Eröffnung benötigen die Organisatoren für jeden Prüfauftrag ein verlässliches Ergebnis. Ein abgewiesener oder langsamer Zugang darf nicht aus dem Bericht verschwinden.
Du vervollständigst eine Prüffunktion in Go und speicherst einen echten JSON-Bericht. Vorausgesetzt werden Go-Funktionen, Structs, Slices, Module und grundlegende Kanalsyntax sowie Building a Lost and Found API oder gleichwertige HTTP-Erfahrung. HTTP-Clientfehler, begrenzte Wartezeiten und die Verantwortung für Antwortressourcen werden vor ihrer Verwendung erklärt. Alle Ziele sind kontrollierte lokale Dienste; dies ist eine einmalige Veranstaltungsprüfung, kein Internetscanner oder Überwachungsdienst. Diese eigenständige Einheit benötigt keine Dateien einer früheren VM. Plane einschließlich Lesen und üblicher Fehler etwa 55 Minuten ein; das ist eine Schätzung des Autors.
Eine kleine erfolgreiche Prüfung lesen
In diesem Schritt führst du ein kleines funktionierendes Beispiel aus und lernst, was ein Ergebnis identifiziert. Beginne in Workspace. Go-Quellcode und lokaler Veranstaltungsdienst sind vorbereitet. Alle folgenden Befehle laufen in Workspace.
cd wählt das Verzeichnis. Go liegt unter /usr/local/go/bin; export setzt dieses Verzeichnis vor den vorhandenen $PATH dieser Shell. Das gilt nur für diese Terminalsitzung. Wiederhole beide Zeilen in einer neuen Shell; globale Shell-Dateien müssen nicht geändert werden.
cd /home/labex/project/site-checker
export PATH=/usr/local/go/bin:$PATH
cat liest Dateien, ohne sie zu bearbeiten. Sieh dir die beiden normalen Aufträge und die Go-Datenstrukturen an:
cat normal.json types.go
Jedes Ziel besitzt eine id für diesen Auftrag, eine anzufragende url und want, den erwarteten Text im Antwortkörper. Das Ergebnis behält id und url; kind bezeichnet den fachlichen Ausgang und status den empfangenen HTTP-Status oder 0, wenn keine Antwortheader eingetroffen sind. Auftrag und URL sind verschieden: Zwei Personen können getrennte Prüfungen desselben Zugangs anfordern.
go run . kompiliert und startet das Go-Paket in diesem Verzeichnis. Der vorbereitete Befehl verwendet -input für eine JSON-Liste, -workers für die maximale Zahl gleichzeitiger Prüfungen und -timeout für das HTTP-Zeitbudget pro Ziel. 200ms bedeutet 200 Millisekunden. Hier prüft ein Worker die beiden schnellen Zugänge nacheinander. Das Shell-Zeichen > schreibt die Standardausgabe in eine Datei und ersetzt eine vorhandene Datei; Fehler erscheinen weiterhin im Terminal.
go run . -input normal.json -workers 1 -timeout 200ms > normal-report.json
Lies das tatsächlich gespeicherte Ergebnis:
cat normal-report.json
Beide Aufträge sollten kind: "ok" und status: 200 mit ihren ursprünglichen IDs und URLs enthalten. 200 bedeutet, dass der Server diesen GET angenommen hat; allein beweist es nicht, dass der erwartete Seiteninhalt vorhanden ist. Der erste Entwurf versteht nur den einfachen Fall. Als Nächstes machst du die Ergebnisse für die übrigen Zugänge aussagekräftig.
Bei go: command not found wiederholst du das export der Sitzung. Wird eine Datei nicht gefunden, wiederhole cd und prüfe ihren Namen. Meldet Go später einen Kompilierungsfehler, verwende Dateiname und Zeilennummer, um diesen kleinen Bereich zu finden und zu reparieren. Der nächste Schritt zeigt, wie du Änderungen bearbeitest, speicherst und prüfst, ohne deine ganze Datei zu ersetzen. Lass main.go, types.go, alle JSON-Eingaben und den vorbereiteten lokalen Dienst unverändert.
Antworten von fehlgeschlagenen Anfragen unterscheiden
In diesem Schritt bearbeitest du die kleine Funktion Check in Workspace, jeweils eine Entscheidung nach der anderen. Lasse run.go sequenziell, damit du dich auf die Bedeutung eines einzelnen Ziels konzentrieren kannst. Lies zuerst den Entwurf:
cat check.go
Das Ergebnis beginnt mit ID und URL dieses Auftrags. client.Get liefert eine Antwort und einen Fehler. Der vorhandene Fehlerzweig behandelt eine fehlgeschlagene Verbindung; ein erfolgreicher Aufruf überträgt dieser Funktion die Verantwortung zum Schließen des Antwortkörpers. Erhalte defer response.Body.Close() unmittelbar nach diesem Fehlerzweig: defer läuft bei der Rückkehr aus der Funktion, auch bei vorzeitiger Rückkehr. Erhalte auch die Zuweisung des empfangenen Status. Du erweiterst diesen Entwurf, statt ihn durch ein bereitgestelltes fertiges Programm zu ersetzen.
Lokal bearbeiten und Fehler beheben
Erstelle vor dem Bearbeiten eine Quelltextsicherung. cp kopiert eine Datei; die Endung .bak ist wichtig, weil eine weitere .go-Datei als Teil dieses Pakets kompiliert würde und Check doppelt definieren könnte.
cp check.go check.go.bak
Öffne die vorhandene Datei im Terminaleditor:
nano check.go
Bewege dich in nano mit den Pfeiltasten. Tippe, um Text einzufügen; Backspace und Delete entfernen Zeichen. Ctrl+K schneidet die aktuelle Zeile aus; verwende es daher nur, wenn diese ganze Zeile entfernt werden soll. Ctrl bedeutet, Control beim Drücken der anderen Taste zu halten. Verwende Ctrl+W, tippe func Check und dann Enter zum Suchen; Ctrl+C bricht eine Suche ab. Bearbeite an der Cursorposition. Drücke zum Speichern Ctrl+O, prüfe, dass der Dateiname weiterhin check.go ist, und drücke Enter. Ctrl+X beendet den Editor. Wiederhole nano check.go, wenn du eine weitere Änderung brauchst. Hast du den falschen Dateinamen geöffnet oder unbeabsichtigt etwas geändert, drücke Ctrl+X und dann N bei der Speicherfrage. Bei einer unerwünschten Dateinamensabfrage bricht Ctrl+C die Abfrage ab. Lies dein Verzeichnis mit pwd, verwende das cd aus dem ersten Schritt und öffne vor einem erneuten Versuch die richtige Datei.
Nach jeder Änderung formatiert gofmt -w check.go die Datei direkt. Eine fehlende Klammer oder ein anderer Syntaxfehler nennt Dateiname und Zeilennummer: Öffne diese Datei erneut, suche die nahe gelegene Anweisung und repariere diesen Bereich. Prüfe nach dem Speichern mit cat check.go, was tatsächlich auf dem Datenträger steht. Erhalte die bereits geschriebenen funktionierenden Teile; ein gewöhnlicher Quelltextfehler erfordert weder einen VM-Reset noch das Überschreiben der gesamten Funktion.
Entscheiden, ob der Server diesen Zugang angenommen hat
Eine 403-Antwort ist ein erfolgreicher HTTP-Austausch; deshalb gibt Get dafür nicht automatisch einen Go-Fehler zurück. Diese Veranstaltung erwartet exakt Status 200; andere empfangene Statuswerte bedeuten http_error. Das ist die fachliche Veranstaltungsregel, keine Behauptung, dass jeder andere 2xx-Status grundsätzlich ein HTTP-Fehler ist.
Schreibe in Check nach dem Speichern von response.StatusCode eine Bedingung, die ihn mit http.StatusOK, der Standardbibliothekskonstante für 200, vergleicht. Setze bei einem anderen Status die Ergebnisart auf "http_error" und gib dieses Ergebnis sofort zurück. Erhalte vorerst das vorhandene abschließende Ergebnis "ok". Diese Rückkehr schließt den Körper über das vorhandene defer, ohne auf das Lesen eines unnötigen Fehlerkörpers zu warten.
Speichere, beende nano und formatiere:
gofmt -w check.go
Sage vor der Ausführung voraus, was normale Aufträge und der Personalauftrag melden sollten. Du kannst alle Aufträge ansehen, ohne sie zu bearbeiten:
cat targets.json
go run . -input targets.json -workers 1 -timeout 200ms
In dieser Phase sollte der Personalauftrag http_error mit 403 sein, während empfangene 200-Seiten weiterhin ok sind, selbst mit falschem Inhalt. Die langsame Ticketprüfung heißt noch connection_error; Timeouts unterscheidest du unten. Diese absichtlich verbleibenden Fehler zeigen, was deine nächsten Änderungen ändern müssen. Jede Eingabe-ID einschließlich beider Anmelde-IDs muss weiterhin ein Ergebnis haben.
Den empfangenen Seiteninhalt prüfen
Bei einer 200-Antwort liefert io.ReadAll(response.Body) Körperbytes und einen Fehler. Ergänze io und strings neben net/http in einer Importgruppe: import ( gefolgt von einem Paketnamen in Anführungszeichen pro Zeile, dann ). Imports benennen Pakete, die deine Datei verwendet; ungenutzte Imports sind Compilerfehler, ergänze sie daher bei der Implementierung ihrer Aufrufe.
Lies einen erfolgreich empfangenen Körper vor der Klassifizierung in body und err. Schlägt das Lesen fehl, gib vorerst ein Ergebnis mit "connection_error" zurück. Erhalte den bereits empfangenen Status im Ergebnis. Setze oder erhalte nach erfolgreichem Lesen zuerst result.Kind = "ok". Prüfe dann nach dieser Zuweisung und vor der abschließenden Rückgabe die erwartete Markierung. string(body) wandelt Bytes in Text um, und strings.Contains(string(body), target.Want) beantwortet, ob dieser Text die Markierung enthält. Ist die Antwort falsch, ändere die Art in "content_mismatch". Weise nach dieser Bedingung nicht erneut "ok" zu, sonst würde dies die Abweichung überschreiben. In Go negiert ! einen booleschen Wert. Erhalte eine abschließende Rückgabe für den erfolgreich gelesenen Körper.
Speichere und beende, formatiere dann und wiederhole dieselben echten Aufträge:
gofmt -w check.go
go run . -input targets.json -workers 1 -timeout 200ms
Nun sollte der falsche Lageplan content_mismatch mit 200 sein, während beide Anmeldeaufträge ok mit 200 und das Personalergebnis http_error mit 403 bleiben. Ein empfangener Status beweist keine passende Markierung. Der Tickettimeout braucht weiterhin eine eigene Kategorie.
Endliches Warten von einem anderen Fehler unterscheiden
Das Budget des HTTP-Clients umfasst das Lesen des Antwortkörpers. Ein Timeout vor den Headern lässt den Status null; ein Timeout nach 200-Headern muss Status 200 erhalten. Ergänze net bei den Imports. Ein net.Error hat eine Methode Timeout(). Dieses kurze Go-Muster prüft vor dem Methodenaufruf, ob ein Fehler diese Schnittstelle unterstützt:
if networkError, ok := err.(net.Error); ok && networkError.Timeout() {
// The operation exceeded its time budget.
}
Die Typzusicherung liefert einen umgewandelten Wert und einen booleschen Wert. && wertet die rechte Seite nur aus, wenn die linke wahr ist. Erhalte sowohl im Anfragefehlerzweig als auch im Körperlesefehlerzweig "connection_error" als Standard und ändere ihn in "timeout", wenn dieser abgesicherte Test erfolgreich ist. Erhalte die Rückgabe jedes Zweigs und die ursprüngliche Auftragsidentität. Speichere, beende und formatiere:
gofmt -w check.go
Der vorhandene Dienst bietet auch zwei hilfreiche kontrollierte Fälle: /garden/bodylate/check sendet vor seiner endlichen Körperverzögerung von 600ms die 200-Header; /garden/deniedbody/check sendet vor derselben unnötigen Körperverzögerung die 403-Header. Erstelle eine zusätzliche Eingabe zur Untersuchung dieser Fälle und lasse alle vorbereiteten JSON-Listen intakt:
nano body-probes.json
Gib dieses JSON-Array ein. JSON verwendet doppelt zitierte Schlüssel und Zeichenfolgen, Kommata zwischen Feldern und Objekten und eckige Klammern um die Liste. Nach dem letzten Feld oder Objekt steht kein Komma.
[
{"id": "body-200", "url": "http://127.0.0.1:8080/garden/bodylate/check", "want": "GARDEN OPEN"},
{"id": "body-403", "url": "http://127.0.0.1:8080/garden/deniedbody/check", "want": "GARDEN OPEN"}
]
Speichere mit Ctrl+O, bestätige body-probes.json und Enter und beende dann mit Ctrl+X. Lies vor der Verwendung die tatsächliche Datei:
cat body-probes.json
Sage beide Ergebnisse voraus und frage sie dann mit 200ms Budget ab:
go run . -input body-probes.json -workers 1 -timeout 200ms
Erwarte für body-200 die Art timeout mit Status 200 und für body-403 die Art http_error mit Status 403. Die Ablehnung ist vor dem Lesen ihres Körpers bekannt; dessen Verzögerung darf sie daher nicht in einen Timeout verwandeln. Der Clienttimeout beendet das Warten; der Server kann seine endliche Arbeit später abschließen. Leite Korrektheit nicht aus der verstrichenen Gesamtdauer ab.
Führe zuletzt die ursprüngliche vollständige Auftragsliste erneut aus:
go run . -input targets.json -workers 1 -timeout 200ms
Ordne anhand der ID zu, nicht anhand der Zeilenposition. Erwarte zwei ok, ein http_error mit 403, ein content_mismatch mit 200, ein timeout mit null und ein connection_error mit null. Fachliche Fehlschläge sind gewöhnliche Berichtswerte, daher endet der Befehl weiterhin erfolgreich. Ein Compiler- oder JSON-Syntaxfehler bedeutet, dass der Befehl seine Aufgabe nicht ausführen konnte: Repariere deine lokale Änderung anhand von Dateiname und Position und wiederhole dann diesen Befehl. Die Kursprüfung untersucht deine ursprünglichen Quellen und das Körperschließverhalten mit unabhängigen Eingaben; sie verlangt weder einen bestimmten Editor noch den zusätzlichen Dateinamen.
Den vollständigen Bericht speichern und lesen
In diesem Schritt speicherst du einen nützlichen Bericht und behältst jeden Auftrag. Lies die vorbereitete sequenzielle Schleife:
cat run.go
http.Client{Timeout: budget} setzt für jede Anfrage ein endliches Zeitbudget. Die Schleife ruft Check einmal pro Ziel auf und hängt jedes Ergebnis an, auch Fehler. Sie darf weder beim ersten fehlgeschlagenen Zugang zurückkehren noch Ergebnisse in einer nach URL indizierten Map sammeln. Das initialisierte leere Slice ergibt außerdem ein leeres JSON-Array, wenn keine Aufträge vorliegen.
Speichere jetzt den vollständigen Bericht. Absichtlich ersetzt wird nur die Berichtsdatei; die Eingabeaufträge bleiben unverändert.
go run . -input targets.json -workers 1 -timeout 200ms > report.json
Lies die tatsächlich erzeugte Datei:
cat report.json
Verfolge mit den IDs die beiden Anmeldeaufträge zur gleichen URL. Jeder muss genau einmal vorkommen. Das 403-Ergebnis sagt den Organisatoren, dass ein Server geantwortet und die Anfrage abgewiesen hat; es ist kein Verbindungsausfall. Die falsche Lageplanmarkierung verlangt trotz Status 200 eine Inhaltsprüfung. Ein Timeout sagt, dass diese Prüfung ihr Budget überschritten hat, nicht dass der Dienst niemals antworten wird.
Probiere zum Schluss die vorbereitete leere Auftragsliste. Die Standardausgabe erscheint direkt und ersetzt deinen nützlichen Bericht daher nicht:
go run . -input empty.json -workers 1 -timeout 200ms
Erwarte [] und ein normales Ende. Behalte report.json, dein aktualisiertes check.go und alle ursprünglichen Eingaben. Die Kursprüfungen lesen diesen Bericht und führen deinen unveränderten Code auch gegen getrennte lokale Testdienste aus; kopierte oder statische Zeilen ersetzen keine echten Anfragen.
Zusammenfassung
Du hast für jeden lokalen Prüfauftrag ein zutreffendes Ergebnis erzeugt, HTTP-Ablehnungen von Transportfehlern unterschieden, falsche Inhalte erkannt, endliche HTTP-Zeitbudgets verwendet und jeden empfangenen Antwortkörper geschlossen. Du hast einen vollständigen JSON-Bericht gespeichert und gelesen und wiederholte URLs als getrennte Auftrags-IDs erhalten. Die nächste Einheit behält diese Entscheidungen und ändert, wie eine kleine Zahl von Workern die Arbeit aufteilt.



