为了账号安全,请及时绑定邮箱和手机立即绑定

保持活动请求 _change 连续供稿

保持活动请求 _change 连续供稿

Go
慕丝7291255 2022-06-01 11:42:02
我正在尝试将以下 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然后我正在接收数据。
查看完整描述

2 回答

?
长风秋雁

TA贡献1757条经验 获得超7个赞

您的代码“按预期”运行,并且您在 Go 中编写的内容并不等同于 Node.js 中显示的代码。继续执行代码块,ioutil.ReadAll(resp.Body)因为连接由 CouchDB 服务器保持打开状态。一旦服务器关闭连接,您的客户端代码将打印出来result,ioutil.ReadAll()以便能够将所有数据读取到 EOF。


从CouchDB 文档中关于连续馈送:


连续提要保持打开并连接到数据库,直到明确关闭,并且在发生更改时将其发送给客户端,即近乎实时的。与 longpoll 提要类型一样,您可以设置超时和心跳间隔,以确保连接保持打开状态以进行新的更改和更新。


您可以尝试实验并添加&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 以进行进一步处理。



查看完整回答
反对 回复 2022-06-01
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

最后,我能够解决这个问题。该问题与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 无法读取。


查看完整回答
反对 回复 2022-06-01
  • 2 回答
  • 0 关注
  • 112 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号