|
|
@ -9,6 +9,7 @@ import ( |
|
|
|
"net" |
|
|
|
"net/http" |
|
|
|
"net/url" |
|
|
|
"regexp" |
|
|
|
"strings" |
|
|
|
"time" |
|
|
|
|
|
|
@ -18,6 +19,8 @@ import ( |
|
|
|
|
|
|
|
const clientHttpTimeout = 60 * time.Second |
|
|
|
|
|
|
|
var reCrLf = regexp.MustCompile(`[\r\n]+`) |
|
|
|
|
|
|
|
// Curl всегде возвращает результат в интерфейс + ошибка (полезно для внешних запросов с неизвестной структурой)
|
|
|
|
// сериализуем в объект, при передаче ссылки на переменную типа
|
|
|
|
func Curl(ctx context.Context, method, urlc, bodyJSON string, response interface{}, headers map[string]string, cookies []*http.Cookie) (result interface{}, err error) { |
|
|
@ -58,8 +61,7 @@ func Curl(ctx context.Context, method, urlc, bodyJSON string, response interface |
|
|
|
// только если в запросе не указаны передаваемые параметры
|
|
|
|
clearUrl := strings.Contains(urlc, "?") |
|
|
|
|
|
|
|
bodyJSON = strings.Replace(bodyJSON, " ", "", -1) |
|
|
|
err = json.Unmarshal([]byte(bodyJSON), &mapValues) |
|
|
|
bodyJSON = reCrLf.ReplaceAllString(bodyJSON, "") |
|
|
|
|
|
|
|
if method == "JSONTOGET" && bodyJSON != "" && clearUrl { |
|
|
|
actionType = "JSONTOGET" |
|
|
@ -70,36 +72,36 @@ func Curl(ctx context.Context, method, urlc, bodyJSON string, response interface |
|
|
|
|
|
|
|
switch actionType { |
|
|
|
case "JSONTOGET": // преобразуем параметры в json в строку запроса
|
|
|
|
if err == nil { |
|
|
|
for k, v := range mapValues { |
|
|
|
values.Set(k, v) |
|
|
|
} |
|
|
|
uri, _ := url.Parse(urlc) |
|
|
|
uri.RawQuery = values.Encode() |
|
|
|
urlc = uri.String() |
|
|
|
req, err = http.NewRequest("GET", urlc, strings.NewReader(bodyJSON)) |
|
|
|
} else { |
|
|
|
fmt.Println("Error! Fail parsed bodyJSON from GET Curl: ", err) |
|
|
|
err = json.Unmarshal([]byte(bodyJSON), &mapValues) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("error Unmarshal in Curl, bodyJSON: %s, err: %s", bodyJSON, err) |
|
|
|
} |
|
|
|
|
|
|
|
for k, v := range mapValues { |
|
|
|
values.Set(k, v) |
|
|
|
} |
|
|
|
uri, _ := url.Parse(urlc) |
|
|
|
uri.RawQuery = values.Encode() |
|
|
|
urlc = uri.String() |
|
|
|
req, err = http.NewRequest("GET", urlc, strings.NewReader(bodyJSON)) |
|
|
|
|
|
|
|
case "JSONTOPOST": // преобразуем параметры в json в тело запроса
|
|
|
|
if err == nil { |
|
|
|
for k, v := range mapValues { |
|
|
|
values.Set(k, v) |
|
|
|
} |
|
|
|
req, err = http.NewRequest("POST", urlc, strings.NewReader(values.Encode())) |
|
|
|
req.PostForm = values |
|
|
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") |
|
|
|
} else { |
|
|
|
fmt.Println("Error! Fail parsed bodyJSON to POST: ", err) |
|
|
|
err = json.Unmarshal([]byte(bodyJSON), &mapValues) |
|
|
|
if err != nil { |
|
|
|
return nil, fmt.Errorf("error Unmarshal in Curl, bodyJSON: %s, err: %s", bodyJSON, err) |
|
|
|
} |
|
|
|
|
|
|
|
for k, v := range mapValues { |
|
|
|
values.Set(k, v) |
|
|
|
} |
|
|
|
req, err = http.NewRequest("POST", urlc, strings.NewReader(values.Encode())) |
|
|
|
req.PostForm = values |
|
|
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded") |
|
|
|
|
|
|
|
default: |
|
|
|
req, err = http.NewRequest(method, urlc, strings.NewReader(bodyJSON)) |
|
|
|
} |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
return "", err |
|
|
|
} |
|
|
|
|
|
|
|
// дополняем переданными заголовками
|
|
|
|
httpClientHeaders(ctx, req, headers) |
|
|
|
|
|
|
@ -125,11 +127,9 @@ func Curl(ctx context.Context, method, urlc, bodyJSON string, response interface |
|
|
|
responseString := string(responseData) |
|
|
|
|
|
|
|
// возвращаем объект ответа, если передано - в какой объект класть результат
|
|
|
|
// НА ОШИБКУ НЕ ПРОВЕРЯТЬ!!!!!!
|
|
|
|
if response != nil { |
|
|
|
err = json.Unmarshal([]byte(responseString), &response) |
|
|
|
if err != nil { |
|
|
|
return "", err |
|
|
|
} |
|
|
|
json.Unmarshal([]byte(responseString), &response) |
|
|
|
} |
|
|
|
|
|
|
|
// всегда отдаем в интерфейсе результат (полезно, когда внешние запросы или сериализация на клиенте)
|
|
|
@ -201,7 +201,7 @@ func PortResolver(port string) (status bool) { |
|
|
|
// ProxyPort свободный порт от прокси с проверкой доступности на локальной машине
|
|
|
|
// если занято - ретраим согласно заданным параметрам
|
|
|
|
func ProxyPort(addressProxy, interval string, maxCountRetries int, timeRetries time.Duration) (port string, err error) { |
|
|
|
port, err = Retrier(maxCountRetries, timeRetries, func() (string, error) { |
|
|
|
port, err = Retrier(maxCountRetries, timeRetries, true, func() (string, error) { |
|
|
|
port, err = AddressProxy(addressProxy, interval) |
|
|
|
if err != nil { |
|
|
|
return "", err |
|
|
@ -231,6 +231,9 @@ func ReadUserIP(r *http.Request) string { |
|
|
|
|
|
|
|
// httpClientHeaders устанавливает заголовки реквеста из контекста и headers
|
|
|
|
func httpClientHeaders(ctx context.Context, req *http.Request, headers map[string]string) { |
|
|
|
if req == nil { |
|
|
|
return |
|
|
|
} |
|
|
|
for ctxField, headerField := range models.ProxiedHeaders { |
|
|
|
if value := getFieldCtx(ctx, ctxField); value != "" { |
|
|
|
req.Header.Add(headerField, value) |
|
|
@ -245,8 +248,18 @@ func httpClientHeaders(ctx context.Context, req *http.Request, headers map[strin |
|
|
|
} |
|
|
|
|
|
|
|
func getFieldCtx(ctx context.Context, name string) string { |
|
|
|
if ctx == nil { |
|
|
|
return "" |
|
|
|
} |
|
|
|
nameKey := "logger." + name |
|
|
|
requestID, _ := ctx.Value(nameKey).(string) |
|
|
|
a := ctx.Value(nameKey) |
|
|
|
if a == nil { |
|
|
|
return "" |
|
|
|
} |
|
|
|
requestID, ok := a.(string) |
|
|
|
if !ok { |
|
|
|
return "" |
|
|
|
} |
|
|
|
|
|
|
|
return requestID |
|
|
|
} |
|
|
|