Go lang RPC返回EOF错误

时间:2017-12-25 16:45:18

标签: go json-rpc

我使用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 个答案:

答案 0 :(得分: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)
}