英文:
http: superfluous response.WriteHeader call 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.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) // -< Error from here
w.Write(data)
}
如果文件夹中只有一个文件,上述代码可以正常工作,但如果文件夹中有多个文件,我会得到错误:http: superfluous response.WriteHeader call
。
我理解这个错误是由于使用了w.WriteHeader(http.StatusOK)
,它不能被多次设置,但我需要它被设置为了让客户端处理返回的数据。
我该如何修改这段代码,以便在处理每个文件后直接将数据返回给客户端。
更新
如果我按照下面的评论建议删除http.StatusOK
,那么返回的将是纯文本而不是JSON!
英文:
In my code, I've a loop that processing set of files (based on what available at pre-specified folder), and based on the output of each processed file, some info is sent to the client, so I wrote the below:
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) // -< Error from here
w.Write(data)
}
Above working correctly if the folder has a single file, but if has more than one, I got the error: http: superfluous response.WriteHeader call
I understood the error is due to using w.WriteHeader(http.StatusOK)
which can not be used more than once to be set, but I need it to be set for the client to process the returned data.
How can I fix this code, so that I can return data directly to the client upon processing each file.
UPDATE
If I remove http.StatusOK
as recommended in the comments below, then I get the returned as plain text not as JSON!
答案1
得分: 1
你不能简单地将JSON文档连接在一起,然后期望结果是有效的JSON编码。你需要将你的output
对象放入一个数组中,然后在最后一次输出该数组,否则响应将不是有效的JSON。
如果你像你的代码一样逐个输出对象,最终的数据将会是这样的:
{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}
每个输出本身都是有效的,但是将对象简单地连接在一起的整个输出是无效的。
理想情况下,当将JSON输出到像HTTP响应这样的流时,不要将其存储在一个中间缓冲区(data
)中,而是使用json.NewEncoder(w)
,其中w
是HTTP响应写入器。流式传输通常比渲染到变量更好。
var outputs = make([]Output, 0, len(files))
for i, file := range files {
uniqueSlice := unique(matches)
outputs = append(outputs, Output{MSG: "ok", File: file, Skills: uniqueSlice})
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(outputs); err != nil {
panic(err)
}
英文:
You can't just concatenate JSON documents together and expect the result to be valid json encoded. You'll have to put your output
objects in an array and then output that array once at the end, otherwise the response won't be valid json.
If you output objects individually like your code did, the final data will look like
{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}{"MSG": "ok", "File": "...", "Skills": [...]}
Each one of those outputs is valid by itself, but the entire output with the objects just concatenated together, is not.
Ideally, when outputting json to a stream like an HTTP response, instead of storing it in an intermediate buffer (data
) for you, use json.NewEncoder(w)
where w
is the http response writer. Streaming is almost always better than rendering to a variable.
var outputs = make([]Output,0,len(files)
for i, file := range files {
uniqueSlice := unique(matches)
outputs = append(outputs, Output{MSG: "ok", File: file, Skills: uniqueSlice})
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(outputs); err != nil {
panic(err)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论