Golang中HTTP:多余的Response.WriteHeader调用问题
Golang中HTTP:多余的Response.WriteHeader调用问题 在我的代码中,有一个循环用于处理一组文件(基于预指定文件夹中可用的文件),并根据每个处理文件的输出,将一些信息发送给客户端,因此我编写了以下代码:
for i, file := range files {
uniqueSlice := unique(matches)
output = Output{MSG: "ok", File: file, Skills: uniqueSlice}
data, err := json.Marshal(output)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // -< 错误来自这里
w.Write(data)
}
如果文件夹中只有一个文件,上述代码可以正常工作,但如果文件超过一个,我就会收到错误:http: superfluous response.WriteHeader call
我理解这个错误是由于使用了 w.WriteHeader(http.StatusOK),它不能被设置多次,但我需要为客户端设置它来处理返回的数据。
如果我移除 http.StatusOK,那么返回的数据将显示为纯文本而不是JSON!
如何修复这段代码,以便我可以在处理每个文件后直接将数据返回给客户端。
更多关于Golang中HTTP:多余的Response.WriteHeader调用问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
无需设置状态为 http.StatusOK,因为这是默认值。同样,也无需显式设置传输编码为分块传输,因为这也是默认设置。
我建议直接创建一个 JSON 编码器,将其输出发送到 HTTP 响应,然后对每个输出对象调用它。
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
for i, file := range files {
uniqueSlice := unique(matches)
output = Output{MSG: "ok", File: file, Skills: uniqueSlice}
encoder.Encode(output)
}
调用 w.Write 要求在之前设置 HTTP 状态码,否则会使用默认的 StatusOK。多次设置状态码会产生多余的日志。
你或许可以尝试使用 http.Flusher 实现分块传输编码。
package main
import (
"io/ioutil"
"log"
"net/http"
"path"
)
func main() {
http.HandleFunc("/files", streamFiles)
err := http.ListenAndServe(":8090", nil)
if err != nil {
log.Fatal(err)
}
}
func streamFiles(w http.ResponseWriter, r *http.Request) {
files, err := ioutil.ReadDir("./files")
if err != nil {
log.Fatal(err)
}
flusher, ok := w.(http.Flusher)
if !ok {
http.NotFound(w, r)
return
}
w.Header().Set("Transfer-Encoding", "chunked")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
for _, f := range files {
buf, err := ioutil.ReadFile(path.Join("./files", f.Name()))
if err != nil {
log.Fatal(err)
}
w.Write(buf)
flusher.Flush()
}
}
问题在于你在循环中多次调用了 WriteHeader 方法。HTTP 响应头只能被设置一次,之后再次调用 WriteHeader 就会触发错误。
解决方案是在循环开始前设置一次响应头,然后在循环内只写入数据。以下是修正后的代码:
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // 在循环外设置一次
for i, file := range files {
uniqueSlice := unique(matches)
output = Output{MSG: "ok", File: file, Skills: uniqueSlice}
data, err := json.Marshal(output)
if err != nil {
panic(err)
}
w.Write(data)
// 如果需要分隔多个JSON对象,可以写入换行符
w.Write([]byte("\n"))
}
如果你需要为每个文件发送独立的 JSON 响应,可以考虑使用流式响应或分块传输编码。以下是使用 http.Flusher 的示例:
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
return
}
for i, file := range files {
uniqueSlice := unique(matches)
output = Output{MSG: "ok", File: file, Skills: uniqueSlice}
data, err := json.Marshal(output)
if err != nil {
panic(err)
}
w.Write(data)
w.Write([]byte("\n"))
flusher.Flush() // 立即发送到客户端
}
如果每个文件处理都需要独立的 HTTP 响应,那么你需要重新设计接口,让客户端为每个文件发起单独的请求,或者使用 WebSocket 等双向通信协议。


