为多个端点设置 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
根据提供的反馈,我倾向于相信这会解决我的问题:
- 删除
MyApp
的单例的使用
- 将 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,您使连接有点有状态,但您的任务似乎需要无状态连接。这种方法可能有问题。
我重复使用 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
根据提供的反馈,我倾向于相信这会解决我的问题:
- 删除
MyApp
的单例的使用
- 将 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,您使连接有点有状态,但您的任务似乎需要无状态连接。这种方法可能有问题。