|
@@ -23,68 +23,75 @@ type AoDunService interface {
|
|
|
GetWhiteStaticList(ctx context.Context,ip string) (int,error)
|
|
|
}
|
|
|
func NewAoDunService(
|
|
|
- service *Service,
|
|
|
+ service *Service,
|
|
|
conf *viper.Viper,
|
|
|
-
|
|
|
) AoDunService {
|
|
|
+ // 1. 创建一个可复用的 Transport,并配置好 TLS 和其他参数
|
|
|
+ tr := &http.Transport{
|
|
|
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 忽略 SSL 验证
|
|
|
+ MaxIdleConns: 100, // 最大空闲连接数
|
|
|
+ IdleConnTimeout: 90 * time.Second, // 空闲连接超时时间
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 基于该 Transport 创建一个可复用的 http.Client
|
|
|
+ client := &http.Client{
|
|
|
+ Transport: tr,
|
|
|
+ Timeout: 15 * time.Second, // 设置所有请求的默认超时时间
|
|
|
+ }
|
|
|
+
|
|
|
return &aoDunService{
|
|
|
Service: service,
|
|
|
- Url: conf.GetString("aodun.Url"),
|
|
|
- clientID: conf.GetString("aodun.clientID"),
|
|
|
- username: conf.GetString("aodun.username"),
|
|
|
- password: conf.GetString("aodun.password"),
|
|
|
- IPusername: conf.GetString("aodunIp.username"),
|
|
|
- IPpassword: conf.GetString("aodunIp.password"),
|
|
|
- domainUserName: conf.GetString("domainWhite.username"),
|
|
|
- domainPassword: conf.GetString("domainWhite.password"),
|
|
|
-
|
|
|
+ Url: conf.GetString("aodun.Url"),
|
|
|
+ clientID: conf.GetString("aodun.clientID"),
|
|
|
+ username: conf.GetString("aodun.username"),
|
|
|
+ password: conf.GetString("aodun.password"),
|
|
|
+ IPusername: conf.GetString("aodunIp.username"),
|
|
|
+ IPpassword: conf.GetString("aodunIp.password"),
|
|
|
+ domainUserName: conf.GetString("domainWhite.username"),
|
|
|
+ domainPassword: conf.GetString("domainWhite.password"),
|
|
|
+ httpClient: client, // 存储共享的 client
|
|
|
}
|
|
|
}
|
|
|
|
|
|
type aoDunService struct {
|
|
|
*Service
|
|
|
- Url string
|
|
|
- clientID string
|
|
|
- username string
|
|
|
- password string
|
|
|
- IPusername string
|
|
|
- IPpassword string
|
|
|
+ Url string
|
|
|
+ clientID string
|
|
|
+ username string
|
|
|
+ password string
|
|
|
+ IPusername string
|
|
|
+ IPpassword string
|
|
|
domainUserName string
|
|
|
domainPassword string
|
|
|
+ httpClient *http.Client // <--- 新增 http client 字段
|
|
|
}
|
|
|
|
|
|
|
|
|
-func (s *aoDunService) sendFormData(ctx context.Context,apiUrl string,tokenType string,token string,formData map[string]interface{}) ([]byte,error) {
|
|
|
+func (s *aoDunService) sendFormData(ctx context.Context, apiUrl string, tokenType string, token string, formData map[string]interface{}) ([]byte, error) {
|
|
|
URL := s.Url + apiUrl
|
|
|
jsonData, err := json.Marshal(formData)
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("序列化请求数据失败: %w", err)
|
|
|
}
|
|
|
- req, err := http.NewRequest("POST", URL, bytes.NewBuffer(jsonData))
|
|
|
+
|
|
|
+ // 使用带有 context 的请求,以便上游可以控制请求的取消
|
|
|
+ req, err := http.NewRequestWithContext(ctx, "POST", URL, bytes.NewBuffer(jsonData))
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("创建 HTTP 请求失败: %w", err)
|
|
|
}
|
|
|
- // 设置请求头 Content-Type 为 "application/json"
|
|
|
- req.Header.Set("Content-Type", "application/json")
|
|
|
- if tokenType == "" {
|
|
|
- req.Header.Set("Authorization", tokenType + " " + token)
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- tr := &http.Transport{
|
|
|
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // <--- 关键修改:忽略 SSL 验证
|
|
|
+ // 设置请求头
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
+ // 修正逻辑:当 token 不为空时才设置 Authorization
|
|
|
+ if token != "" {
|
|
|
+ req.Header.Set("Authorization", tokenType+" "+token)
|
|
|
}
|
|
|
|
|
|
- // 5. 使用 HTTP 客户端发送请求
|
|
|
- client := &http.Client{
|
|
|
- Transport: tr,
|
|
|
- Timeout: 15 * time.Second, // 设置一个合理的超时时间,例如15秒
|
|
|
- }
|
|
|
- resp, err := client.Do(req)
|
|
|
+ // 使用结构体中共享的 httpClient 实例发送请求
|
|
|
+ resp, err := s.httpClient.Do(req)
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("发送 HTTP 请求失败: %w", err)
|
|
|
}
|
|
|
- // defer 确保在函数返回前关闭响应体,防止资源泄露
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
// 6. 读取响应体内容
|
|
@@ -96,7 +103,7 @@ func (s *aoDunService) sendFormData(ctx context.Context,apiUrl string,tokenType
|
|
|
}
|
|
|
|
|
|
|
|
|
-func (s *aoDunService) sendDomainFormData(ctx context.Context,domain string,ip string,apiType string) ([]byte,error) {
|
|
|
+func (s *aoDunService) sendDomainFormData(ctx context.Context, domain string, ip string, apiType string) ([]byte, error) {
|
|
|
var URL string
|
|
|
if apiType == "add" {
|
|
|
URL = "http://zapi.zzybgp.com/api/user/do_main"
|
|
@@ -110,29 +117,20 @@ func (s *aoDunService) sendDomainFormData(ctx context.Context,domain string,ip s
|
|
|
formData.Add("do_main_list[ip]", ip)
|
|
|
encodedData := formData.Encode()
|
|
|
|
|
|
- req, err := http.NewRequest("POST", URL, bytes.NewBuffer([]byte(encodedData)))
|
|
|
+ // 使用带有 context 的请求
|
|
|
+ req, err := http.NewRequestWithContext(ctx, "POST", URL, bytes.NewBuffer([]byte(encodedData)))
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("创建 HTTP 请求失败: %w", err)
|
|
|
}
|
|
|
|
|
|
- // 设置请求头 Content-Type 为 "application/x-www-form-urlencoded"
|
|
|
+ // 设置请求头
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
|
|
-
|
|
|
- tr := &http.Transport{
|
|
|
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // <--- 关键修改:忽略 SSL 验证
|
|
|
- }
|
|
|
-
|
|
|
- // 5. 使用 HTTP 客户端发送请求
|
|
|
- client := &http.Client{
|
|
|
- Transport: tr,
|
|
|
- Timeout: 15 * time.Second, // 设置一个合理的超时时间,例如15秒
|
|
|
- }
|
|
|
- resp, err := client.Do(req)
|
|
|
+ // 使用共享的 httpClient 实例发送请求
|
|
|
+ resp, err := s.httpClient.Do(req)
|
|
|
if err != nil {
|
|
|
return nil, fmt.Errorf("发送 HTTP 请求失败: %w", err)
|
|
|
}
|
|
|
- // defer 确保在函数返回前关闭响应体,防止资源泄露
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
// 6. 读取响应体内容
|
|
@@ -144,7 +142,19 @@ func (s *aoDunService) sendDomainFormData(ctx context.Context,domain string,ip s
|
|
|
}
|
|
|
|
|
|
|
|
|
-func (s *aoDunService) GetToken(ctx context.Context) (string,string,error) {
|
|
|
+// sendAuthenticatedRequest 封装了需要认证的API请求的通用流程:获取token -> 发送请求。
|
|
|
+func (s *aoDunService) sendAuthenticatedRequest(ctx context.Context, apiPath string, formData map[string]interface{}) ([]byte, error) {
|
|
|
+ tokenType, token, err := s.GetToken(ctx)
|
|
|
+ if err != nil {
|
|
|
+ // 如果获取token失败,直接返回错误
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用获取到的token发送请求
|
|
|
+ return s.sendFormData(ctx, apiPath, tokenType, token, formData)
|
|
|
+}
|
|
|
+
|
|
|
+func (s *aoDunService) GetToken(ctx context.Context) (string, string, error) {
|
|
|
|
|
|
formData := map[string]interface{}{
|
|
|
"ClientID": s.clientID,
|
|
@@ -178,21 +188,17 @@ func (s *aoDunService) GetToken(ctx context.Context) (string,string,error) {
|
|
|
return responsePayload.TokenType,responsePayload.AccessToken, nil
|
|
|
}
|
|
|
|
|
|
-func (s *aoDunService) AddWhiteStaticList(ctx context.Context,req []v1.IpInfo) error {
|
|
|
- tokenType,token, err := s.GetToken(ctx)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
+func (s *aoDunService) AddWhiteStaticList(ctx context.Context, req []v1.IpInfo) error {
|
|
|
formData := map[string]interface{}{
|
|
|
- "action" : "add",
|
|
|
- "bwflag" : "white",
|
|
|
+ "action": "add",
|
|
|
+ "bwflag": "white",
|
|
|
"insert_bw_list": req,
|
|
|
}
|
|
|
|
|
|
- resBody, err := s.sendFormData(ctx,"/v1.0/firewall/static_bw_list",tokenType,token,formData)
|
|
|
+ // 使用封装好的方法发送认证请求
|
|
|
+ resBody, err := s.sendAuthenticatedRequest(ctx, "/v1.0/firewall/static_bw_list", formData)
|
|
|
if err != nil {
|
|
|
- return err
|
|
|
+ return err
|
|
|
}
|
|
|
// 7. 将响应体 JSON 数据反序列化到 ResponsePayload 结构体
|
|
|
var res v1.IpResponse
|
|
@@ -212,20 +218,16 @@ func (s *aoDunService) AddWhiteStaticList(ctx context.Context,req []v1.IpInfo) e
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (s *aoDunService) GetWhiteStaticList(ctx context.Context,ip string) (int,error) {
|
|
|
- tokenType,token, err := s.GetToken(ctx)
|
|
|
- if err != nil {
|
|
|
- return 0, err
|
|
|
- }
|
|
|
-
|
|
|
+func (s *aoDunService) GetWhiteStaticList(ctx context.Context, ip string) (int, error) {
|
|
|
formData := map[string]interface{}{
|
|
|
- "action" : "get",
|
|
|
- "bwflag" : "white",
|
|
|
- "page" : 1,
|
|
|
- "ids": ip,
|
|
|
+ "action": "get",
|
|
|
+ "bwflag": "white",
|
|
|
+ "page": 1,
|
|
|
+ "ids": ip,
|
|
|
}
|
|
|
|
|
|
- resBody, err := s.sendFormData(ctx,"/v1.0/firewall/static_bw_list",tokenType,token,formData)
|
|
|
+ // 使用封装好的方法发送认证请求
|
|
|
+ resBody, err := s.sendAuthenticatedRequest(ctx, "/v1.0/firewall/static_bw_list", formData)
|
|
|
if err != nil {
|
|
|
return 0, err
|
|
|
}
|
|
@@ -256,19 +258,15 @@ func (s *aoDunService) GetWhiteStaticList(ctx context.Context,ip string) (int,er
|
|
|
}
|
|
|
|
|
|
func (s *aoDunService) DelWhiteStaticList(ctx context.Context, id string) error {
|
|
|
- tokenType, token, err := s.GetToken(ctx)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
formData := map[string]interface{}{
|
|
|
"action": "del",
|
|
|
"bwflag": "white",
|
|
|
"flag": 0,
|
|
|
- "ids": id,
|
|
|
+ "ids": id,
|
|
|
}
|
|
|
|
|
|
- resBody, err := s.sendFormData(ctx, "/v1.0/firewall/static_bw_list", tokenType, token, formData)
|
|
|
+ // 使用封装好的方法发送认证请求
|
|
|
+ resBody, err := s.sendAuthenticatedRequest(ctx, "/v1.0/firewall/static_bw_list", formData)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|