为多个端点设置 http 客户端?

Go http client setup for multiple endpoints?

我重复使用 http 客户端连接来对单个端点进行外部调用。节目摘录如下:

var AppCon MyApp

func New(user, pass string, platformURL *url.URL, restContext string) (*MyApp, error) {
  if AppCon == (MyApp{}) {
      AppCon = MyApp{
          user:        user,
          password:    pass,
          URL:         platformURL,
          Client:      &http.Client{Timeout: 30 * time.Second},
          RESTContext: restContext,
      }

      cj, err := cookiejar.New(nil)
      if err != nil {
          return &AppCon, err
      }

      AppCon.cookie = cj
  }

    return &AppCon, nil
}

// This is an example only. There are many more functions which accept *MyApp as a pointer.
func(ma *MyApp) GetUser(name string) (string, error){
   // Return user
}

func main(){   
    for {
      // Get messages from a queue 
      // The message returned from the queue provide info on which methods to call
      // 'm' is a struct with message metadata

      c, err := New(m.un, m.pass, m.url)

      go func(){
        // Do something i.e c.GetUser("123456")
      }()
    }
}

我现在需要建立一个客户端连接,通过队列消息接收到不同的 endpoints/credentials。

我预见的问题是我不能简单地用新的端点详细信息修改 AppCon,因为返回指向 MyApp 的指针,导致重置 c。这可能会影响 goroutine 对意外端点进行 HTTP 调用。更重要的是,该程序并不意味着要了解端点(我正在考虑使用 switch 语句),而是通过队列消息接收它需要的东西。

鉴于我提出的问题是正确的,有没有关于如何解决它的建议?

编辑 1

根据提供的反馈,我倾向于相信这会解决我的问题:

  1. 删除 MyApp
  2. 的单例的使用
  3. 将 http 客户端与 MyApp 分离,这将使它能够重用
var httpClient *http.Client

func New(user, pass string, platformURL *url.URL, restContext string) (*MyApp, error) {

    AppCon = MyApp{
          user:        user,
          password:    pass,
          URL:         platformURL,
          Client:      func() *http.Client {
      if httpClient == nil {
        httpClient = &http.Client{Timeout: 30 * time.Second}
      }
        return httpClient
    }()
          RESTContext: restContext,
      }

    return &AppCon, nil
}

// This is an example only. There are many more functions which accept *MyApp as a pointer.
func(ma *MyApp) GetUser(name string) (string, error){
   // Return user
}

func main(){   
    for {
      // Get messages from a queue 
      // The message returned from the queue provide info on which methods to call
      // 'm' is a struct with message metadata

      c, err := New(m.un, m.pass, m.url)

      // Must pass a reference
      go func(c *MyApp){
        // Do something i.e c.GetUser("123456")
      }(c)
    }
}

免责声明:这不是对您问题的直接回答,而是试图指导您找到解决问题的正确方法。

  • 尽量避免使用单例模式 MyApp。此外,New 具有误导性,它实际上并不是每次都创建一个新对象。相反,您可以每次都创建一个新实例,同时保留 http 客户端连接。
  • 不要使用这样的结构:AppCon == (MyApp{}),总有一天你会射中你的腿。改用指针并将其与 nil.
  • 进行比较
  • 避免竞争条件。在您的代码中,您启动一​​个 goroutine 并立即进行 for 循环的新迭代。考虑到您重新使用整个 MyApp 实例,您实际上引入了竞争条件。
  • 使用 cookie,您使连接有点有状态,但您的任务似乎需要无状态连接。这种方法可能有问题。