Compare commits

...

1 Commits

Author SHA1 Message Date
nanhe 1233c07df9 feat: support custom httpClient 2025-03-26 17:59:12 +08:00
4 changed files with 132 additions and 29 deletions
+35
View File
@@ -0,0 +1,35 @@
{
"scope": "darabonba",
"name": "HttpClient",
"version": "0.0.1",
"main": "./main.dara",
"maintainers": [
{
"name": "Alibaba Cloud SDK",
"email": "sdk-team@alibabacloud.com"
}
],
"libraries": {
},
"releases": {
"go": "github.com/alibabacloud-go/tea/tea:v1.2.3-0.20240605082020-e6e537a31150"
},
"go": {
"interface": true,
"clientName": "HttpClient",
"typedef": {
"HttpRequest": {
"import": "net/http",
"type": "http.Request"
},
"HttpResponse": {
"import": "net/http",
"type": "http.Response"
},
"HttpTransport": {
"import": "net/http",
"type": "http.Transport"
}
}
}
}
+8
View File
@@ -0,0 +1,8 @@
typedef HttpRequest;
typedef HttpResponse;
typedef HttpTransport;
init(){
}
async function call(request: HttpRequest, transport: HttpTransport): HttpResponse;
+47 -19
View File
@@ -31,7 +31,28 @@ import (
var debugLog = debug.Init("tea")
var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
type HttpRequest interface {
}
type HttpResponse interface {
}
type HttpClient interface {
Call(request *http.Request, transport *http.Transport) (response *http.Response, err error)
}
type teaClient struct {
sync.Mutex
httpClient *http.Client
ifInit bool
}
func (client *teaClient) Call(request *http.Request, transport *http.Transport) (response *http.Response, err error) {
response, err = client.httpClient.Do(request)
return
}
var hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return fn
}
@@ -97,12 +118,7 @@ type RuntimeObject struct {
Listener utils.ProgressListener `json:"listener" xml:"listener"`
Tracker *utils.ReaderTracker `json:"tracker" xml:"tracker"`
Logger *utils.Logger `json:"logger" xml:"logger"`
}
type teaClient struct {
sync.Mutex
httpClient *http.Client
ifInit bool
HttpClient
}
var clientPool = &sync.Map{}
@@ -143,6 +159,9 @@ func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject {
if runtime["logger"] != nil {
runtimeObject.Logger = runtime["logger"].(*utils.Logger)
}
if runtime["httpClient"] != nil {
runtimeObject.HttpClient = runtime["httpClient"].(HttpClient)
}
return runtimeObject
}
@@ -351,18 +370,27 @@ func DoRequest(request *Request, requestRuntime map[string]interface{}) (respons
}
httpRequest.Host = StringValue(request.Domain)
client := getTeaClient(runtimeObject.getClientTag(StringValue(request.Domain)))
client.Lock()
if !client.ifInit {
trans, err := getHttpTransport(request, runtimeObject)
if err != nil {
return nil, err
}
client.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond
client.httpClient.Transport = trans
client.ifInit = true
var client HttpClient
if runtimeObject.HttpClient == nil {
client = getTeaClient(runtimeObject.getClientTag(StringValue(request.Domain)))
} else {
client = runtimeObject.HttpClient
}
client.Unlock()
trans, err := getHttpTransport(request, runtimeObject)
if err != nil {
return
}
if defaultClient, ok := client.(*teaClient); ok {
defaultClient.Lock()
if !defaultClient.ifInit || defaultClient.httpClient.Transport == nil {
defaultClient.httpClient.Transport = trans
}
defaultClient.httpClient.Timeout = time.Duration(IntValue(runtimeObject.ReadTimeout)) * time.Millisecond
defaultClient.ifInit = true
defaultClient.Unlock()
}
for key, value := range request.Headers {
if value == nil || key == "content-length" {
continue
@@ -384,7 +412,7 @@ func DoRequest(request *Request, requestRuntime map[string]interface{}) (respons
putMsgToMap(fieldMap, httpRequest)
startTime := time.Now()
fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05")
res, err := hookDo(client.httpClient.Do)(httpRequest)
res, err := hookDo(client.Call)(httpRequest, trans)
fieldMap["{cost}"] = time.Since(startTime).String()
completedBytes := int64(0)
if runtimeObject.Tracker != nil {
+42 -10
View File
@@ -487,11 +487,36 @@ func Test_GetBackoffTime(t *testing.T) {
utils.AssertEqual(t, true, IntValue(ms) <= 3)
}
type httpClient struct {
HttpClient
httpClient *http.Client
}
func newHttpClient() (*httpClient, error) {
client := new(httpClient)
err := client.Init()
return client, err
}
func (client *httpClient) Init() (_err error) {
return nil
}
func (client *httpClient) Call(request *http.Request, transport *http.Transport) (_result *http.Response, _err error) {
if transport != nil {
trans := transport.Clone()
client.httpClient.Transport = trans
} else {
client.httpClient.Transport = http.DefaultTransport.(*http.Transport).Clone()
}
return client.httpClient.Do(request)
}
func Test_DoRequest(t *testing.T) {
origTestHookDo := hookDo
defer func() { hookDo = origTestHookDo }()
hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
return func(req *http.Request) (*http.Response, error) {
hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return mockResponse(200, ``, errors.New("Internal error"))
}
}
@@ -530,8 +555,8 @@ func Test_DoRequest(t *testing.T) {
utils.AssertNil(t, resp)
utils.AssertContains(t, err.Error(), ` invalid URL escape "%gf"`)
hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
return func(req *http.Request) (*http.Response, error) {
hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return mockResponse(200, ``, nil)
}
}
@@ -579,8 +604,8 @@ func Test_DoRequest(t *testing.T) {
utils.AssertNil(t, err)
utils.AssertEqual(t, "test", StringValue(resp.Headers["tea"]))
hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
return func(req *http.Request) (*http.Response, error) {
hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return func(req *http.Request, transport *http.Transport) (*http.Response, error) {
utils.AssertEqual(t, "tea-cn-hangzhou.aliyuncs.com:1080", req.Host)
return mockResponse(200, ``, errors.New("Internal error"))
}
@@ -592,13 +617,20 @@ func Test_DoRequest(t *testing.T) {
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, resp)
utils.AssertEqual(t, `Internal error`, err.Error())
httpClient, err := newHttpClient()
utils.AssertNil(t, err)
runtimeObj["httpClient"] = httpClient
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, resp)
utils.AssertEqual(t, `Internal error`, err.Error())
}
func Test_DoRequestWithConcurrent(t *testing.T) {
origTestHookDo := hookDo
defer func() { hookDo = origTestHookDo }()
hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
return func(req *http.Request) (*http.Response, error) {
hookDo = func(fn func(req *http.Request, transport *http.Transport) (*http.Response, error)) func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return mockResponse(200, ``, nil)
}
}
@@ -694,11 +726,11 @@ func Test_SetDialContext(t *testing.T) {
}
func Test_hookdo(t *testing.T) {
fn := func(req *http.Request) (*http.Response, error) {
fn := func(req *http.Request, transport *http.Transport) (*http.Response, error) {
return nil, errors.New("hookdo")
}
result := hookDo(fn)
resp, err := result(nil)
resp, err := result(nil, nil)
utils.AssertNil(t, resp)
utils.AssertEqual(t, "hookdo", err.Error())
}