猿问

多个 response.WriteHeader 在非常简单的例子中调用?

我有最基本的 net/http 程序,我用它来学习 Go 中的命名空间:


package main


import (

    "fmt"

    "log"

    "net/http"

)


func main() {

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

        fmt.Println(r.URL)

        go HandleIndex(w, r)

    })


    fmt.Println("Starting Server...")

    log.Fatal(http.ListenAndServe(":5678", nil))

}


func HandleIndex(w http.ResponseWriter, r *http.Request) {

    w.WriteHeader(200)

    w.Write([]byte("Hello, World!"))

}

当我运行程序并localhost:5678在 Chrome 中连接时,我在控制台中得到了这个:


Starting Server...

/

2015/01/15 13:41:29 http: multiple response.WriteHeader calls

/favicon.ico

2015/01/15 13:41:29 http: multiple response.WriteHeader calls

但我不明白这怎么可能。我打印了URL,启动一个新的goroutine,一旦写了标题,并给它一个静态的身体Hello, World!好像一两件事情正在发生。幕后的某些东西正在编写另一个标头,或者以某种方式HandleIndex为同一请求调用两次。我该怎么做才能停止编写多个标题?


编辑:它似乎与该go HandleIndex(w, r)行有关,因为如果我删除go并使其成为函数调用而不是 goroutine,我不会遇到任何问题并且浏览器会获取它的数据。由于它是一个 goroutine,我收到多个 WriteHeader 错误并且浏览器不显示“Hello World”。为什么让它成为一个 goroutine 破坏它?


梦里花落0921
浏览 168回答 3
3回答

慕后森

看一下您注册为传入请求处理程序的匿名函数:func(w http.ResponseWriter, r *http.Request) {    fmt.Println(r.URL)    go HandleIndex(w, r)}它打印 URL(到标准输出),然后调用HandleIndex()一个新的 goroutine 并继续执行。如果你有一个处理函数,你在第一次调用之前没有设置响应状态Write,Go 会自动将响应状态设置为 200(HTTP OK)。如果处理函数没有向响应写入任何内容(并且没有设置响应状态并正常完成),也被视为成功处理请求,并且响应状态 200 将被发送回。您的匿名函数没有设置它,它甚至没有向响应写入任何内容。所以 Go 会这样做:将响应状态设置为 200 HTTP OK。请注意,处理每个请求都在其自己的 goroutine 中运行。因此,如果您调用HandleIndex新的 goroutine,您的原始匿名函数将继续:它将结束,因此将设置响应标头 - 同时(同时)您启动的新 goroutine 也将设置响应标头 - 因此出现"multiple response.WriteHeader calls"错误。如果您删除"go",您的HandleIndex函数将在您的处理程序函数返回之前在同一个 goroutine 中设置响应头,并且“net/http”将知道这一点并且不会再次尝试设置响应头,因此您遇到的错误将不会发生。

红颜莎娜

您已经收到了解决您问题的正确答案,我将提供有关一般情况的一些信息(此类错误经常出现)。从文档中,您看到WriteHeader发送了一个 http 状态代码,并且您不能发送超过 1 个状态代码。如果你有Write任何东西,这相当于发送 200 状态代码然后写东西。因此,如果您w.WriteHeader多次明确使用或使用w.Writebefore ,则会出现您看到的消息w.WriteHeader。

Smart猫小萌

从文档:// WriteHeader sends an HTTP response header with status code. // If WriteHeader is not called explicitly, the first call to Write  // will trigger an implicit WriteHeader(http.StatusOK).在您的情况下发生的事情是您go HandleIndex从处理程序启动。第一个处理程序完成。标准 WriteHeader 写入 ResponseWriter。然后 go 例程 HandleIndex 被启动,它也尝试写一个标题并写入。只需go从 HandleIndex 中删除它,它就会起作用。
随时随地看视频慕课网APP

相关分类

Go
我要回答