wenzuochao 6 лет назад
Родитель
Сommit
8823e83f8b
6 измененных файлов с 189 добавлено и 11 удалено
  1. 14 0
      README.md
  2. 14 0
      README_zh.md
  3. 0 1
      integration/api_test.go
  4. 65 1
      integration/core_test.go
  5. 27 0
      sdk/client.go
  6. 69 9
      sdk/client_test.go

+ 14 - 0
README.md

@@ -116,6 +116,20 @@ client.SetHTTPSInsecure(true)                         // Set client HTTPSInsecur
 isInsecure := client.GetHTTPSInsecure()               // Get client HTTPSInsecure.
 isInsecure := client.GetHTTPSInsecure()               // Get client HTTPSInsecure.
 ```
 ```
 
 
+## HTTP Proxy
+
+If you want to use http proxy or https proxy, you can set environment variables `HTTP_PROXY` or `HTTPS_PROXY`, or you can configure client with config.
+
+```go
+rawurl, _ := url.Parse("http://117.215.227.125:8888") //You should replace the IP with you want
+httpTransport := http.Transport{
+    Proxy:  http.ProxyURL(rawurl)
+}
+config := sdk.NewConfig()
+            .WithHttpTransport(&httpTransport)
+ecsClient, err := ecs.NewClientWithOptions(config)
+```
+
 ## Keep-alive
 ## Keep-alive
 
 
 Alibaba Cloud Go SDK uses primordial `net/http` of Go language to send and accept requests,so it's  configuration is the same as `net/http`'s,you can use config to deliver configuration to the bottomed httpClient.
 Alibaba Cloud Go SDK uses primordial `net/http` of Go language to send and accept requests,so it's  configuration is the same as `net/http`'s,you can use config to deliver configuration to the bottomed httpClient.

+ 14 - 0
README_zh.md

@@ -107,6 +107,20 @@ client.SetHTTPSInsecure(true)                         // 设置客户端 HTTPSIn
 isInsecure := client.GetHTTPSInsecure()               // 获取客户端 HTTPSInsecure
 isInsecure := client.GetHTTPSInsecure()               // 获取客户端 HTTPSInsecure
 ```
 ```
 
 
+## HTTP 代理
+
+如果您想使用 http 代理或 https 代理,您可以设置环境变量 `HTTP_PROXY` 或者 `HTTPS_PROXY`,您也可以使用 config 配置客户端。
+
+```go
+rawurl, _ := url.Parse("http://117.215.227.125:8888") //You should replace the IP with you want
+httpTransport := http.Transport{
+    Proxy:  http.ProxyURL(rawurl)
+}
+config := sdk.NewConfig()
+            .WithHttpTransport(&httpTransport)
+ecsClient, err := ecs.NewClientWithOptions(config)
+```
+
 ## Keep-alive
 ## Keep-alive
 阿里云 Go SDK 底层使用 Go 语言原生的 `net/http` 收发请求,因此配置方式与 `net/http` 相同,您可以通过 config 直接将配置传递给底层的 httpClient
 阿里云 Go SDK 底层使用 Go 语言原生的 `net/http` 收发请求,因此配置方式与 `net/http` 相同,您可以通过 config 直接将配置传递给底层的 httpClient
 
 

+ 0 - 1
integration/api_test.go

@@ -11,7 +11,6 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
-
 	"net/http"
 	"net/http"
 	"net/http/httptest"
 	"net/http/httptest"
 	"os"
 	"os"

+ 65 - 1
integration/core_test.go

@@ -1,6 +1,10 @@
 package integration
 package integration
 
 
 import (
 import (
+	"net/http"
+	"net/http/httptest"
+	"net/http/httputil"
+	"net/url"
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
@@ -145,7 +149,6 @@ func Test_DescribeClustersWithCommonRequestWithROAWithSTStoken(t *testing.T) {
 	credential := assumeresponse.Credentials
 	credential := assumeresponse.Credentials
 	client, err := sdk.NewClientWithStsToken(os.Getenv("REGION_ID"), credential.AccessKeyId, credential.AccessKeySecret, credential.SecurityToken)
 	client, err := sdk.NewClientWithStsToken(os.Getenv("REGION_ID"), credential.AccessKeyId, credential.AccessKeySecret, credential.SecurityToken)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
-	assert.Nil(t, err)
 	request := requests.NewCommonRequest()
 	request := requests.NewCommonRequest()
 	request.Method = "GET"
 	request.Method = "GET"
 	request.Domain = "cs.aliyuncs.com"
 	request.Domain = "cs.aliyuncs.com"
@@ -239,3 +242,64 @@ func Test_CreateInstanceWithCommonRequestWithPolicy(t *testing.T) {
 	assert.NotNil(t, err)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "User not authorized to operate on the specified resource, or this API doesn't support RAM.")
 	assert.Contains(t, err.Error(), "User not authorized to operate on the specified resource, or this API doesn't support RAM.")
 }
 }
+
+func handlerTrue(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(200)
+	w.Write([]byte("test"))
+	return
+}
+
+func handlerFake(w http.ResponseWriter, r *http.Request) {
+	trueserver := handlerTrueServer()
+	url, err := url.Parse(trueserver.URL)
+	if err != nil {
+		return
+	}
+	proxy := httputil.NewSingleHostReverseProxy(url)
+	w.Write([]byte("sdk"))
+	proxy.ServeHTTP(w, r)
+
+	return
+}
+
+func handlerFakeServer() (server *httptest.Server){
+	server = httptest.NewServer(http.HandlerFunc(handlerFake))
+
+	return server
+}
+
+func handlerTrueServer() (server *httptest.Server){
+	server = httptest.NewServer(http.HandlerFunc(handlerTrue))
+
+	return server
+}
+
+func Test_HTTPProxy(t *testing.T) {
+
+	ts := handlerFakeServer()
+	ts1 := handlerTrueServer()
+	defer func() {
+		ts.Close()
+		ts1.Close()
+	}()
+	client, err := sdk.NewClientWithAccessKey(os.Getenv("REGION_ID"), os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"))
+	assert.Nil(t, err)
+	request := requests.NewCommonRequest()
+	domain := strings.Replace(ts1.URL, "http://", "", 1)
+	request.Domain = domain
+	request.Version = "2015-12-15"
+	request.TransToAcsRequest()
+	resp, err := client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.Equal(t, 200, resp.GetHttpStatus())
+	assert.Equal(t, "test", resp.GetHttpContentString())
+
+	originEnv := os.Getenv("HTTP_PROXY")
+	os.Setenv("HTTP_PROXY", ts.URL)
+	resp, err = client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.Equal(t, 200, resp.GetHttpStatus())
+	assert.Equal(t, "sdktest", resp.GetHttpContentString())
+
+	os.Setenv("HTTP_PROXY", originEnv)
+}

+ 27 - 0
sdk/client.go

@@ -20,6 +20,8 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"net/http"
 	"net/http"
+	"net/url"
+	"os"
 	"runtime"
 	"runtime"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -122,6 +124,27 @@ func (client *Client) GetConnectTimeout() time.Duration {
 	return client.connectTimeout
 	return client.connectTimeout
 }
 }
 
 
+func getHttpProxy(scheme string) *url.URL {
+	var proxy *url.URL
+	if scheme == "https" {
+		if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
+			proxy, _ = url.Parse(rawurl)
+		}
+		if rawurl := os.Getenv("https_proxy"); rawurl != "" && proxy == nil {
+			proxy, _ = url.Parse(rawurl)
+		}
+	} else {
+		if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
+			proxy, _ = url.Parse(rawurl)
+		}
+		if rawurl := os.Getenv("http_proxy"); rawurl != "" && proxy == nil {
+			proxy, _ = url.Parse(rawurl)
+		}
+	}
+
+	return proxy
+}
+
 // EnableAsync enable the async task queue
 // EnableAsync enable the async task queue
 func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
 func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
 	client.asyncTaskQueue = make(chan func(), maxTaskQueueSize)
 	client.asyncTaskQueue = make(chan func(), maxTaskQueueSize)
@@ -368,6 +391,7 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		return
 		return
 	}
 	}
 	client.setTimeout(request)
 	client.setTimeout(request)
+	proxy := getHttpProxy(httpRequest.URL.Scheme)
 
 
 	// Set whether to ignore certificate validation.
 	// Set whether to ignore certificate validation.
 	// Default InsecureSkipVerify is false.
 	// Default InsecureSkipVerify is false.
@@ -375,6 +399,9 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		trans.TLSClientConfig = &tls.Config{
 		trans.TLSClientConfig = &tls.Config{
 			InsecureSkipVerify: client.getHTTPSInsecure(request),
 			InsecureSkipVerify: client.getHTTPSInsecure(request),
 		}
 		}
+		if proxy != nil {
+			trans.Proxy = http.ProxyURL(proxy)
+		}
 		client.httpClient.Transport = trans
 		client.httpClient.Transport = trans
 	}
 	}
 
 

+ 69 - 9
sdk/client_test.go

@@ -19,8 +19,10 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
+	"net/http/httptest"
 	"os"
 	"os"
 	"strconv"
 	"strconv"
+	"strings"
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
@@ -160,7 +162,33 @@ func Test_DoAction(t *testing.T) {
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	assert.Equal(t, 200, response.GetHttpStatus())
 	assert.Equal(t, 200, response.GetHttpStatus())
 	assert.Equal(t, "", response.GetHttpContentString())
 	assert.Equal(t, "", response.GetHttpContentString())
+
+	originEnv := os.Getenv("https_proxy")
+	os.Setenv("https_proxy", "https://127.0.0.1:9000")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	assert.Nil(t, client.config.HttpTransport)
+
+	originEnv1 := os.Getenv("http_proxy")
+	os.Setenv("http_proxy", "http://127.0.0.1:8888")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans, _ := client.httpClient.Transport.(*http.Transport)
+	url, _ := trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "http")
+	assert.Equal(t, url.Host, "127.0.0.1:8888")
+
+	request.Scheme = "https"
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans, _ = client.httpClient.Transport.(*http.Transport)
+	url, _ = trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "https")
+	assert.Equal(t, url.Host, "127.0.0.1:9000")
+
 	client.Shutdown()
 	client.Shutdown()
+	os.Setenv("https_proxy", originEnv)
+	os.Setenv("http_proxy", originEnv1)
 	assert.Equal(t, false, client.isRunning)
 	assert.Equal(t, false, client.isRunning)
 }
 }
 
 
@@ -197,6 +225,33 @@ func Test_DoAction_HTTPSInsecure(t *testing.T) {
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	trans = client.httpClient.Transport.(*http.Transport)
 	trans = client.httpClient.Transport.(*http.Transport)
 	assert.Equal(t, false, trans.TLSClientConfig.InsecureSkipVerify)
 	assert.Equal(t, false, trans.TLSClientConfig.InsecureSkipVerify)
+
+	originEnv := os.Getenv("HTTP_PROXY")
+	os.Setenv("HTTP_PROXY", "http://127.0.0.1:9000")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	assert.Nil(t, client.config.HttpTransport)
+
+	originEnv1 := os.Getenv("HTTPS_PROXY")
+	os.Setenv("HTTPS_PROXY", "https://127.0.0.1:8888")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans = client.httpClient.Transport.(*http.Transport)
+	url, _ := trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "https")
+	assert.Equal(t, url.Host, "127.0.0.1:8888")
+
+	request.Scheme = "http"
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans = client.httpClient.Transport.(*http.Transport)
+	url, _ = trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "http")
+	assert.Equal(t, url.Host, "127.0.0.1:9000")
+
+	client.Shutdown()
+	os.Setenv("HTTP_PROXY", originEnv)
+	os.Setenv("HTTPS_PROXY", originEnv1)
 }
 }
 
 
 func Test_DoAction_Timeout(t *testing.T) {
 func Test_DoAction_Timeout(t *testing.T) {
@@ -275,13 +330,22 @@ func Test_ProcessCommonRequest(t *testing.T) {
 	assert.Equal(t, "", resp.GetHttpContentString())
 	assert.Equal(t, "", resp.GetHttpContentString())
 }
 }
 
 
+func mockServer(status int, json string) (server *httptest.Server) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(status)
+		w.Write([]byte(json))
+		return
+	}))
+	return ts
+}
+
 func Test_DoAction_With500(t *testing.T) {
 func Test_DoAction_With500(t *testing.T) {
 	client, err := NewClientWithAccessKey("regionid", "acesskeyid", "accesskeysecret")
 	client, err := NewClientWithAccessKey("regionid", "acesskeyid", "accesskeysecret")
 	assert.Nil(t, err)
 	assert.Nil(t, err)
 	assert.NotNil(t, client)
 	assert.NotNil(t, client)
 	assert.Equal(t, true, client.isRunning)
 	assert.Equal(t, true, client.isRunning)
 	request := requests.NewCommonRequest()
 	request := requests.NewCommonRequest()
-	request.Domain = "ecs.aliyuncs.com"
 	request.Version = "2014-05-26"
 	request.Version = "2014-05-26"
 	request.ApiName = "DescribeInstanceStatus"
 	request.ApiName = "DescribeInstanceStatus"
 
 
@@ -289,16 +353,12 @@ func Test_DoAction_With500(t *testing.T) {
 	request.QueryParams["PageSize"] = "30"
 	request.QueryParams["PageSize"] = "30"
 	request.TransToAcsRequest()
 	request.TransToAcsRequest()
 	response := responses.NewCommonResponse()
 	response := responses.NewCommonResponse()
-	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) {
-			return mockResponse(500, "Server Internel Error", nil)
-		}
-	}
+	ts := mockServer(500, "Server Internel Error")
+	defer ts.Close()
+	domain := strings.Replace(ts.URL, "http://", "", 1)
+	request.Domain = domain
 	err = client.DoAction(request, response)
 	err = client.DoAction(request, response)
 	assert.NotNil(t, err)
 	assert.NotNil(t, err)
-	assert.Equal(t, "SDK.ServerError\nErrorCode: \nRecommend: \nRequestId: \nMessage: Server Internel Error", err.Error())
 	assert.Equal(t, 500, response.GetHttpStatus())
 	assert.Equal(t, 500, response.GetHttpStatus())
 	assert.Equal(t, "Server Internel Error", response.GetHttpContentString())
 	assert.Equal(t, "Server Internel Error", response.GetHttpContentString())
 }
 }