-1

我正在开发一个服务器应用程序,它也是其他后端应用程序的客户端。这是我的基于 http.Client 的客户端:

type Client struct {
   http.Client
   token Token
}

type Token struct {
   tokenString string
   mx sync.RWMutex
}

// e.g. readlock
func (c *Client) getDataWithRetries(req *http.Request) (*http.Response, error) {
    var res *http.Response
    var err error
    var status int
    c.token.mx.RLock()
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer "+c.token.tokenString)
    c.token.mx.RUnlock()
    for i := 0; i < 5; i++ {
        if c.token.tokenString == "" || status == 401 {
            if err := c.setToken(); err != nil {
                log.Println("401")
                return nil, err
            }
            c.token.mx.RLock()
            req.Header.Set("Authorization", "Bearer "+c.token.tokenString)
            c.token.mx.RUnlock()
        }

        res, err = c.Do(req)
        if err != nil {
            log.Println("Do req err")
            return nil, err
        }
        status = res.StatusCode
        if res.StatusCode != 401 {
            break
        }
    }
    if status == 401 { 
        return nil, domain.ErrUnauthorized
    }
    return res, nil
}
// Here's where I write to token
func (c *Client) setToken() error {
    tokenURL := os.Getenv("TOKEN_URL")
    if tokenURL == "" {
        return domain.ErrTokenURLNotFound
    }
    
    req, err := http.NewRequest(http.MethodGet, tokenURL, nil)
    if err != nil {
        return err
    }
    req.SetBasicAuth(c.username, c.password)
    res, err := c.Do(req)
    if err != nil {
        return err
    }
    defer res.Body.Close()
    var dst bytes.Buffer
    if _, err := io.Copy(&dst, res.Body); err != nil {
        return err
    }
    c.token.mx.Lock()
    defer c.token.mx.Unlock()
    var token string
    if err := json.Unmarshal(dst.Bytes(), &token); err != nil {
        log.Println("unmarshal error", err)
        return err
    }
    c.token.tokenString = token
    return nil
}

我将客户端传递给整个应用程序,它会在其中进行一些连续的 API 调用,并将令牌添加为授权标头。令牌每 20 分钟过期一次,我必须通过从令牌颁发 API 获取它来设置一个新令牌。我相信那是我进行数据竞赛的时候。我尝试使用 RWMutex,但到目前为止帮助不大。

我真的不需要该令牌对于每个请求都相同,只要它没有过期,我就可以走了。令牌发行 API 可以同时发行我想要的任意数量的有效令牌。此外,由于多个用户试图同时访问我的应用程序,我是否会在令牌过期之前获得数据竞争?

4

0 回答 0