Оставить в живых запрос на _change непрерывной подачи - PullRequest
0 голосов
/ 25 апреля 2020

Я пытаюсь преобразовать ниже nodejs код в Go. Я должен установить sh поддерживать HTTP-запрос к серверу PouchDB _changes? Feed = непрерывный. Тем не менее, я не могу добиться этого в 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();

Ниже приведен код Go

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 ie. http://localhost: 3030 / загрузки / _changes? Feed = longpoll тогда я получаю данные.

Ответы [ 2 ]

0 голосов
/ 29 апреля 2020

Наконец-то я смог решить проблему. Проблема была связана с флагом 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, следовательно полученные данные были сжаты и, соответственно, Body.Read не смог прочитать.

0 голосов
/ 26 апреля 2020

Ваш код работает "как положено", и то, что вы написали в Go, не эквивалентно коду, показанному в Node.js. Go кодовые блоки на 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() для обработки частичных буферов. Вот очень упрощенный фрагмент кода, который демонстрирует это и должен дать вам основную c идею:

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 содержит нечто, похожее на действительное сообщение, а затем передайте его в канал или обработчик для дальнейшей обработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...