2016-02-22 7 views
9

Ich versuche zu lernen Go Web-Programmierung, und hier ist ein einfacher Webserver: Es druckt die Zeiten aufgerufen werden.Warum dieser einfache Webserver gerade Nummer genannt wird?

package main 

import (
    "fmt" 
    "net/http" 
) 

var calls int 

// HelloWorld print the times being called. 
func HelloWorld(w http.ResponseWriter, r *http.Request){ 
    calls++ 
    fmt.Fprintf(w, "You've called me %d times", calls) 
} 

func main() { 
    fmt.Printf("Started server at http://localhost%v.\n", 5000) 
    http.HandleFunc("/", HelloWorld) 
    http.ListenAndServe(":5000", nil) 
} 

Wenn ich die Seite aktualisieren, ich habe:

You've called me 1 times 
You've called me 3 times 
You've called me 5 times 
.... 

Frage: Warum ist es 1, 3, 5-mal, anstatt 1,2,3 ...? In welcher Reihenfolge wird die Funktion HelloWorld aufgerufen?

+2

Drucken Sie die Anfrage-URI, um zusätzliche Anfragen von Ihrem Browser zu sehen. – dit

Antwort

11

Dies liegt daran, dass jede eingehende Anforderung an die Handlerfunktion HelloWorld() weitergeleitet wird und der Browser mehrere Aufrufe unter der Haube ausführt, speziell an /favicon.ico.

Und da Ihr Webserver kein gültiges Favicon zurücksendet, wird es beim Aktualisieren der Seite im Browser erneut angefordert.

Probieren Sie es mit Chrome: Öffnen Sie die Developer Tools (STRG + UMSCHALT + I), und wählen Sie die Registerkarte "Netzwerk". Hit Refresh, und Sie werden zwei neue Einträge sehen:

Name   Status Type 
-------------------------------------------------------- 
localhost  200  document 
favicon.ico 200  text/plain 

Da Ihr Zähler beginnt mit 0 (Standardwert für Typ int), erhöhen Sie es einmal und Sie zurückschicken 1. Dann wird die Anforderung für favicon.ico erneut erhöht (2), aber das Ergebnis wird nicht angezeigt. Dann, wenn Sie aktualisieren, wird es wieder auf 3 inkrementiert und Sie senden das zurück usw.

Beachten Sie auch, dass mehrere goroutines Anfragen gleichzeitig bedienen können, so dass Ihre Lösung ein Rennen hat. Sie sollten den Zugriff auf die calls Variable synchronisieren, oder verwenden Sie das sync/atomic Paket, um den Zähler sicher zum Beispiel zu erhöhen:

var calls int64 

func HelloWorld(w http.ResponseWriter, r *http.Request) { 
    count := atomic.AddInt64(&calls, 1) 
    fmt.Fprintf(w, "You've called me %d times", count) 
} 

Ein einfaches „fix“ zu erreichen, was Sie würden wollen, den Antrag Pfad zu überprüfen, und wenn es ist nicht die Wurzel "/", nicht erhöhen, zum Beispiel:

func HelloWorld(w http.ResponseWriter, r *http.Request) { 
    if r.URL.Path != "/" { 
     return 
    } 
    count := atomic.AddInt64(&calls, 1) 
    fmt.Fprintf(w, "You've called me %d times", count) 
} 

Sie auch für favicon.ico nur Anfragen ausschließen können, zum Beispiel:

if r.URL.Path == "/favicon.ico" { 
    return 
}