我正在尝试将下面的nodejs代码转换为Go。我必须对PouchDB服务器的_changes?feed = continuous建立保持活动的http请求。但是,我无法在Go中实现它。
var http = require('http')
var agent = new http.Agent({
keepAlive: true
});
var options = {
host: 'localhost',
port: '3030',
method: 'GET',
path: '/downloads/_changes?feed=continuous&include_docs=true',
agent
};
var req = http.request(options, function(response) {
response.on('data', function(data) {
let val = data.toString()
if(val == '\n')
console.log('newline')
else {
console.log(JSON.parse(val))
//to close the connection
//agent.destroy()
}
});
response.on('end', function() {
// Data received completely.
console.log('end');
});
response.on('error', function(err) {
console.log(err)
})
});
req.end();
下面是转到代码
client := &http.Client{}
data := url.Values{}
req, err := http.NewRequest("GET", "http://localhost:3030/downloads/_changes?feed=continuous&include_docs=true", strings.NewReader(data.Encode()))
req.Header.Set("Connection", "keep-alive")
resp, err := client.Do(req)
fmt.Println(resp.Status)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
我的状态为200,但是没有数据被打印,卡住了。另一方面,如果我使用longpoll选项,即。 http://localhost:3030/downloads/_changes?feed=longpoll然后我正在接收数据。
您的代码正在“按预期运行”,并且您在Go中编写的内容与Node.js中显示的代码不同。在ioutil.ReadAll(resp.Body)
上执行代码块,因为CouchDB服务器保持连接打开。服务器关闭连接后,您的客户端代码将打印出result
,因为ioutil.ReadAll()
将能够读取所有数据,直到EOF。
从CouchDB documentation开始连续进纸:
一个连续的提要保持打开状态并连接到数据库,直到显式关闭为止,并且在更改发生时即几乎实时地将更改发送到客户端。与longpoll feed类型一样,您可以设置超时间隔和心跳间隔,以确保连接保持打开状态以进行新的更改和更新。
您可以尝试进行实验,并将&timeout=1
添加到URL,这将迫使CouchDB在1秒后关闭连接。然后,您的Go代码应打印出整个响应。
Node.js代码的工作原理不同,每次服务器发送一些数据时都会调用事件data
处理程序。如果要实现相同并处理部分更新(在关闭连接之前),则不能使用ioutil.ReadAll(),因为它等待EOF(并因此阻塞),而需要使用resp.Body.Read()
之类的方法来处理部分缓冲区。这是一个非常简化的代码片段,演示了这一点,并应给您基本概念:
package main
import (
"fmt"
"net/http"
"net/url"
"strings"
)
func main() {
client := &http.Client{}
data := url.Values{}
req, err := http.NewRequest("GET", "http://localhost:3030/downloads/_changes?feed=continuous&include_docs=true", strings.NewReader(data.Encode()))
req.Header.Set("Connection", "keep-alive")
resp, err := client.Do(req)
defer resp.Body.Close()
fmt.Println(resp.Status)
if err != nil {
fmt.Println(err)
}
buf := make([]byte, 1024)
for {
l, err := resp.Body.Read(buf)
if l == 0 && err != nil {
break // this is super simplified
}
// here you can send off data to e.g. channel or start
// handler goroutine...
fmt.Printf("%s", buf[:l])
}
fmt.Println()
}
在现实世界中的应用程序中,您可能希望确保buf
拥有看起来像有效消息的内容,然后将其传递给通道或处理程序goroutine进行进一步处理。
最后,我能够解决此问题。该问题与DisableCompression
标志有关。 https://github.com/golang/go/issues/16488这个问题给了我一些提示。
通过设置DisableCompression: true
解决了该问题。client := &http.Client{Transport: &http.Transport{
DisableCompression: true,
}}
[我假设client := &http.Client{}
默认情况下发送DisableCompression : false
,pouchdb服务器正在发送压缩的json,因此接收到的数据被压缩,并且resp.Body.Read无法读取。