多个response.WriteHeader调用真的很简单的例子?

Cor*_*urn 30 http go server

我有最基本的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!"))
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

编辑:它似乎与该go HandleIndex(w, r)行有关,因为如果我删除go并只是使它成为函数调用而不是goroutine,我没有任何问题,浏览器获取它的数据.由于它是goroutine,我得到多个WriteHeader错误,浏览器不显示"Hello World".为什么要把这个打破呢?

icz*_*cza 53

看一下您注册为传入请求处理程序的匿名函数:

func(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.URL)
    go HandleIndex(w, r)
}
Run Code Online (Sandbox Code Playgroud)

它打印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"会知道这个并且不会再尝试设置响应头,所以你遇到的错误将会不会发生.

  • @CoreyOgburn从[`http.Serve()`](http://golang.org/pkg/net/http/#Serve)的文档中引用:`"Serve接受侦听器l上的传入HTTP连接,创建一个新的为每个人服务goroutine."` (3认同)

Sal*_*ali 5

您已经收到了解决您问题的正确答案,我将提供有关一般情况的一些信息(此类错误经常出现)。

文档中,您看到WriteHeader发送了一个 http 状态代码,并且您不能发送超过 1 个状态代码。如果你有Write任何东西,这相当于发送 200 状态代码然后写东西。

因此,如果您w.WriteHeader多次明确使用或使用w.Writebefore ,则会出现您看到的消息w.WriteHeader