关于Go语言的Http请求

170 阅读4分钟

我觉得这三个知识点非常好,概括了 Go 语言中 SOCKS5 代理的实现,包括 HTTP 请求处理和 SOCKS5 连接请求的身份验证与连接管理,强调了协议结构、数据读取、错误处理和连接管理的重要性。

屏幕截图 2024-11-11 211844.png 代码分析

1.包导入:导入了必要的包,包括格式化输出、文件操作、日志记录、HTTP 请求处理和字符串处理。

2.创建 HTTP 客户端:创建一个 HTTP 客户端实例,用于发送请求。 client := &http.Client{}

  1. 构建请求数据:使用 strings.NewReader 创建一个请求体,内容为 JSON 格式的数据。 req, err := http.NewRequest("POST", "https://XXXXXt", data) if err != nil { log.Fatal(err) }

  2. 使用 http.NewRequest 创建一个新的 POST 请求,指定 URL 和请求体。

发送请求:使用 client.Do(req) 发送请求并获取响应。

-关闭响应体并读取响应内容,最后打印输出。

知识点总结 HTTP 客户端:使用 http.Client 发送 HTTP 请求。 请求构建:使用 http.NewRequest 创建请求,支持自定义请求方法和请求体。 请求头:通过 req.Header.Set 方法设置请求头,影响请求的处理方式。 错误处理:使用 log.Fatal 处理错误,确保程序在遇到错误时能够及时反馈。 响应处理:使用 ioutil.ReadAll 读取响应体,确保在使用后关闭响应体以释放资源。 这段代码展示了 Go 语言在处理 HTTP 请求时的基本用法,适合用于与 RESTful API 进行交互。

image.png

代码分析 常量定义:

  • 定义了 SOCKS5 协议中使用的常量,包括版本号、命令类型和地址类型。 process 函数: func process(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) err := auth(reader, conn) if err != nil { log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err) return } log.Println("auth success") }
  • 该函数处理与客户端的连接,首先关闭连接以释放资源。 使用 bufio.NewReader 创建一个读取器来读取连接数据。 调用 auth 函数进行身份验证,如果失败则记录错误并返回。 auth 函数: func auth(reader *bufio.Reader, conn net.Conn) (err error) { ver, err := reader.ReadByte() if err != nil { return fmt.Errorf("read ver failed:%w", err) } if ver != socks5Ver { return fmt.Errorf("not supported ver:%v", ver) } // 读取方法数量 methodSize, err := reader.ReadByte() if err != nil { return fmt.Errorf("read method size failed:%w", err) } method := make([]byte, methodSize) _, err = io.ReadFull(reader, method) if err != nil { return fmt.Errorf("read method failed:%w", err) } log.Println("ver:", ver, "method:", method) // 发送响应 _, err = conn.Write([]byte{socks5Ver, 0x00}) if err != nil { return fmt.Errorf("write failed:%w", err) } return nil }
  • 该函数负责处理 SOCKS5 的身份验证。 首先读取版本号并检查是否为 SOCKS5。 然后读取方法数量和具体方法,记录日志。 最后发送身份验证成功的响应。 知识点总结 SOCKS5 协议:了解 SOCKS5 协议的基本结构,包括版本号、命令和地址类型。 错误处理:使用 fmt.Errorf 进行错误处理,提供详细的错误信息。 数据读取:使用 bufio.Reader 和 io.ReadFull 读取数据,确保完整性。 连接管理:使用 defer 语句确保连接在处理完成后被关闭,避免资源泄漏。 日志记录:通过 log.Printf 和 log.Println 记录重要信息,便于调试和监控。

image.png

代码分析 connect 函数:

  • 该函数处理 SOCKS5 连接请求。 首先创建一个缓冲区并读取数据。 检查版本号和命令类型,确保它们符合 SOCKS5 协议。 地址类型处理: switch atype { case atypeIPv4: err = io.ReadFull(reader, buf[4:8]) if err != nil { return fmt.Errorf("read atype failed:%w", err) } addr := net.IP(buf[4:8]) case atypeHOST: hostSize := buf[4] host := make([]byte, hostSize) err = io.ReadFull(reader, host) if err != nil { return fmt.Errorf("read hostSize failed:%w", err) } addr = string(host) case atypeIPv6: addr = make([]byte, net.IPv6len) err = io.ReadFull(reader, addr) if err != nil { return fmt.Errorf("read IPv6 failed:%w", err) } default: return errors.New("invalid atype") }
  • 根据地址类型(IPv4、主机名或IPv6)读取目标地址。 使用 switch 语句处理不同的地址类型,确保正确读取数据。 端口处理:
  • 从缓冲区中读取端口号,并将其转换为大端格式。 记录目标地址和端口,准备进行连接。 发送响应:
  • 发送连接成功的响应给客户端,包含版本号、响应状态、地址类型、目标地址和端口。 process 函数: func process(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) err := auth(reader, conn) if err != nil { log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err) return } log.Println("auth success") err = connect(reader, conn) if err != nil { log.Printf("client %v connect failed:%v", conn.RemoteAddr(), err) return } }
  • 该函数处理与客户端的连接,首先进行身份验证,然后调用 connect 函数处理连接请求。 知识点总结 SOCKS5 协议:了解 SOCKS5 协议的请求结构,包括版本号、命令类型和地址类型。 数据读取:使用 io.ReadFull 确保完整读取数据,避免数据丢失。 地址类型处理:根据不同的地址类型(IPv4、主机名、IPv6)进行相应的处理。 错误处理:使用 fmt.Errorf 提供详细的错误信息,便于调试。 连接管理:确保在处理完成后关闭连接,避免资源泄漏