在开始发送正文之前,服务器可以多次发送HTTP标头作为响应。例如,clickhouse这样做是为了报告进度。
发件人https://clickhouse.tech/docs/en/interfaces/http/amp/:
X-ClickHouse-Progress: {"read_rows":"2752512","read_bytes":"240570816","total_rows_to_read":"8880128"}
X-ClickHouse-Progress: {"read_rows":"5439488","read_bytes":"482285394","total_rows_to_read":"8880128"}
X-ClickHouse-Progress: {"read_rows":"8783786","read_bytes":"819092887","total_rows_to_read":"8880128"}
如何在Go中读取更新标头?当我试图得到回应的价值。标头多次保持不变。
下面是我用来获取更新头的代码片段。
//
// Create query
//
progressQ := fmt.Sprintf("SELECT * from system.numbers limit 10000000")
ctx, cancel := context.WithTimeout(be.ctx, time.Second*15)
defer cancel()
//
// Prepare HTTP request
//
req, err := http.NewRequestWithContext(ctx, http.MethodPost, be.url, strings.NewReader(progressQ))
if err != nil {
return err
}
//
// Set URL query
//
q := req.URL.Query()
q.Set("wait_end_of_query", "1")
q.Set("send_progress_in_http_headers", "1")
req.URL.RawQuery = q.Encode()
//
// Perform request
//
resp, err := be.cli.Do(req)
if err != nil {
return err
}
for {
select {
case <-time.After(time.Second / 10):
fmt.Println(resp.Header.Values("X-Clickhouse-Summary"))
case <-ctx.Done():
goto after
}
}
after:
结果看起来像
[{"read_rows":"10002432","read_bytes":"80019456","written_rows":"0","written_bytes":"0","total_rows_to_read":"0"}]
[{"read_rows":"10002432","read_bytes":"80019456","written_rows":"0","written_bytes":"0","total_rows_to_read":"0"}]
[{"read_rows":"10002432","read_bytes":"80019456","written_rows":"0","written_bytes":"0","total_rows_to_read":"0"}]
这与我在中看到的例子不同https://altinity.com/blog/2018/9/28/progress-reports-for-long-running-queries-via-http-protocol
标准库无法满足您的要求。
在返回*http.Response
对象之前,标准库的HTTP客户端会等待,直到读取了所有标头。
您需要实现自己的HTTP客户端才能获得这种行为。
您可以利用http.Transport
类型的DialContext字段来包装标准http.Client
使用的标准网络层。这可以允许您在标准库解析响应之前对其进行检查,并可能在读取标头时报告标头。
我看到您的代码段有问题:当"X-ClickHouse-Progress"
中报告进度时,您正在请求"X-Clickhouse-Summary"
。如果您更改了标头名称,它应该会返回您期望获得的标头值片段。
正如@Flimzy所提到的,golang HTTP标准库将同时返回所有头。所以循环中没有多余的点。