go-resty / resty

Simple HTTP and REST client library for Go
MIT License
9.89k stars 696 forks source link

Problem with a client requesting a TCP service #723

Closed uptutu closed 10 months ago

uptutu commented 11 months ago

This's an awesome tool, Thank you to all the contributors for their efforts!

But I'm experiencing some confusion in using it

I have a TCP service for receiving client requests (I'll give the code below), I've tried using the HTTP Native Client, and the Postman request receives a response from the server, but in resty it gives an error:

http_client_test.go:23: read tcp 172.27.175.75:46696->172.27.175.75:23360: read: connection reset by peer

TCP Server Code

# -*- coding: UTF-8 -*-
import socket

host = "0.0.0.0"   # 替换成自己的ip 地址
port = 23360
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))

while True:
    s.listen()
    # print("正在监听端口")
    conn, addr = s.accept()
    # print('连接的地址和端口:', addr)
    data = conn.recv(4096)
    data = data.decode()
    if not data:
        break
    # body_start = data.find("\r\n\r\n") + 4
    # body = data[body_start:]
    print('Accepted data:', data)

    print("\n")
    # conn.sendall(language.get(data, 'Nothing').encode())
    # conn.send()
    with open('received_request.txt', 'a') as request_file:
        request_file.write(data+'\n')
    # 响应行
    response_line = "HTTP/1.1 200 OK\r\n"

    # 响应头
    response_header = "Server:Python20WS/2.1\r\n"

    # 响应空行
    response_blank = "\r\n"

    # 响应主体
    response_body = "{'code': '0', 'msg': ''}"

    # 拼接响应报文
    response_data = response_line + response_header + response_blank + response_body
    # 发送响应报文
    conn.send((response_data.encode()))
    with open('sent_response.txt', 'a') as response_file:
        response_file.write(response_data+'\n')
    conn.close()
s.close()

Resty Test Code

var _once sync.Once
var _httpClient *resty.Client

func httpClient() *resty.Client {
    if _httpClient == nil {
        _once.Do(func() {
            _httpClient = resty.NewWithClient(&http.Client{Transport: http.DefaultTransport})
            _httpClient.SetTimeout(_defaultHTTPRequestTimeout)
            _httpClient.JSONMarshal = sonic.Marshal
            _httpClient.JSONUnmarshal = sonic.Unmarshal
            _httpClient.SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
                req.Close = true
                return nil
            })
        })
    }
    return _httpClient
}

func TestHTTPClient(t *testing.T) {
    ticker := time.Tick(3 * time.Second)
    for {
        <-ticker
        if resp, err := httpClient().R().
            SetHeader("Content-Type", "text/plain").
            SetBody(strings.NewReader(`Hi`)).
            SetContentLength(true).
            Post("http://172.27.175.75:23360"); err != nil {
            t.Log(err)
        } else {
            t.Log(resp)
        }
        return
    }
}

Native Go HTTP Client Test Code

func TestHTTPNative(t *testing.T) {
    url := "http://172.27.175.75:23360"
    method := "POST"

    payload := strings.NewReader(`Hi`)

    req, err := http.NewRequest(method, url, payload)

    if err != nil {
        fmt.Println(err)
        return
    }
    req.Header.Add("Content-Type", "text/plain")
    req.Header.Add("Connection", "close")

    res, err := httpClient().GetClient().Do(req)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer res.Body.Close()

    time.Sleep(2 * time.Second)

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(body))
}
jeevatkm commented 11 months ago

@uptutu Can you change this line from

_httpClient = resty.NewWithClient(&http.Client{Transport: http.DefaultTransport})

to

_httpClient = resty.New()

Try and share your feedback.

uptutu commented 11 months ago

@uptutu Can you change this line from

_httpClient = resty.NewWithClient(&http.Client{Transport: http.DefaultTransport})

to

_httpClient = resty.New()

Try and share your feedback.

I use resty.New() by default, but no matter what I change, the problem persists!

jeevatkm commented 10 months ago

@uptutu I see then I will have to try your code snippet(s) locally. Let me give it a try!

jeevatkm commented 10 months ago

@uptutu I have tried your code; it does work correctly for the default HTTP and Resty client. Regarding the connection reset by a peer, you should look into it at your end.

I have tried this on my end (I commented out the lines not present on my end and your code).

package main

import (
    "fmt"
    "io"
    "net/http"
    "strings"
    "sync"
    "time"

    "github.com/go-resty/resty/v2"
)

func main() {
    url := "http://0.0.0.0:23360"
    method := "POST"

    payload := strings.NewReader(`Hi`)

    req, err := http.NewRequest(method, url, payload)

    if err != nil {
        fmt.Println(err)
        return
    }
    req.Header.Add("Content-Type", "text/plain")
    req.Header.Add("Connection", "close")

    res, err := httpClient().GetClient().Do(req)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer res.Body.Close()

    time.Sleep(2 * time.Second)

    body, err := io.ReadAll(res.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("Response from server:", string(body))

    // Resty Code
    resp, err := httpClient().R().
        SetHeader("Content-Type", "text/plain").
        SetBody(strings.NewReader(`Hi`)).
        SetContentLength(true).
        Post(url)
    fmt.Println("Resty code, response from server:", resp, err)
}

var _once sync.Once
var _httpClient *resty.Client

func httpClient() *resty.Client {
    if _httpClient == nil {
        _once.Do(func() {
            _httpClient = resty.NewWithClient(&http.Client{Transport: http.DefaultTransport})
            // _httpClient.SetTimeout(_defaultHTTPRequestTimeout)
            // _httpClient.JSONMarshal = sonic.Marshal
            // _httpClient.JSONUnmarshal = sonic.Unmarshal
            _httpClient.SetPreRequestHook(func(c *resty.Client, req *http.Request) error {
                req.Close = true
                return nil
            })
        })
    }
    return _httpClient
}

Output:

Response from server: {'code': '0', 'msg': ''}
Resty code, response from server: {'code': '0', 'msg': ''} read tcp 127.0.0.1:59384->127.0.0.1:23360: read: connection reset by peer