Go lang RPC return EOF error

Я использую http для вызова RPC с кодом ниже

func (c *CallClient) Wallet(method string, req, rep interface{}) error {
    client := &http.Client{}
    data, _ :=  EncodeClientRequest(method, req)
    reqest, _ := http.NewRequest("POST", c.endpoint, bytes.NewBuffer(data))
    resp, err := client.Do(reqest)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    io.Copy(ioutil.Discard, resp.Body)
    return DecodeClientResponse(resp.Body, rep)
}

с EncodeClientRquest && DecodeClientResponse

// EncodeClientRequest кодирует параметры для запроса клиента JSON-RPC.

func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
    c := &clientRequest{
        Version: "2.0",
        Method: method,
        Params: [1]interface{}{args},
        Id:     uint64(rand.Int63()),
    }

    return json.Marshal(c)
}

// DecodeClientResponse декодирует тело ответа клиентского запроса // в ответ интерфейса.

func DecodeClientResponse(r io.Reader, reply interface{}) error {
    var c clientResponse
    if err := json.NewDecoder(r).Decode(&c); err != nil {
        return err
    }
    if c.Error != nil {
        return fmt.Errorf("%v", c.Error)
    }
    if c.Result == nil {
        return errors.New("result is null")
    }
    return json.Unmarshal(*c.Result, reply)
}

И я получил ошибку EOF.

1 ответ

Эта строка:

io.Copy(ioutil.Discard, resp.Body)

читает весь resp.Bodyоставляя читателю больше нет байтов для чтения. Поэтому любые последовательные призывы к resp.Body.Read вернет EOF и json.Decoder.Decode метод использует io.Reader.Read метод при декодировании содержимого данного читателя, так что...

И с тех пор resp.Body является io.ReadCloserИнтерфейс, который не поддерживает "перемотку", и вы хотите читать содержимое тела более одного раза (ioutil.Discard и json.Decode), вам придется читать тело в переменную, которую вы можете перезаписать. прочитайте потом. Это зависит от вас, как вы это делаете, кусок байтов или bytes.Reader, или что-то другое.

Пример использования bytes.Reader:

func (c *CallClient) Wallet(method string, req, rep interface{}) error {
    client := &http.Client{}
    data, err := EncodeClientRequest(method, req)
    if err != nil {
        return err
    }
    reqest, err := http.NewRequest("POST", c.endpoint, bytes.NewBuffer(data))
    if err != nil {
        return err
    }
    resp, err := client.Do(reqest)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // get a reader that can be "rewound"
    buf := bytes.NewBuffer(nil)
    if _, err := io.Copy(buf, resp.Body); err != nil {
        return err
    }
    br := bytes.NewReader(buf.Bytes())

    if _, err := io.Copy(ioutil.Discard, br); err != nil {
        return err
    }

    // rewind
    if _, err := br.Seek(0, 0); err != nil {
        return err
    }
    return DecodeClientResponse(br, rep)
}
Другие вопросы по тегам