Repository: nacos-group/nacos-sdk-go (go)

Issue:
[version compatibility] success field of nacos server's response is empty
### What version of nacos-sdk-go are you using?
v2.2.2

### What version of nacos-sever are you using?
2.0.3

### What version of Go are you using (`go version`)?
go version go1.21.5 darwin/arm64

### What operating system (Linux, Windows, …) and version?

### What did you do?
If possible, provide a recipe for reproducing the error.
![image](https://github.com/nacos-group/nacos-sdk-go/assets/38815080/02c178c5-0465-4251-8c7a-0e6ce8585a17)


As you can see, there is no `field` for `success` in `response`, resulting in `unmarshal` to `success` in response being set to `false`. However, `resultCode` is 200, which means that the result of the request is successful.

-------

可以看到，`response`中没有`success`这个`field`，导致`unmarshal`到response中的`success`被设置成`false`。但是`resultCode`为`200`，表示这个请求的结果是成功的。

### What did you expect to see?

### What did you see instead?


Pull request description:
[version compatibility] fix up when response.ResultCode is 200 but response.Success is false
fix #698 

Patch:
diff --git a/common/remote/rpc/grpc_connection.go b/common/remote/rpc/grpc_connection.go
index dd4934b..3bb9bf2 100644
--- a/common/remote/rpc/grpc_connection.go
+++ b/common/remote/rpc/grpc_connection.go
@@ -18,7 +18,6 @@ package rpc
 
 import (
 	"context"
-	"encoding/json"
 	"time"
 
 	"github.com/golang/protobuf/ptypes/any"
@@ -65,9 +64,7 @@ func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int6
 		return nil, errors.Errorf("request:%s,unsupported response type:%s", request.GetRequestType(),
 			responsePayload.Metadata.GetType())
 	}
-	response := responseFunc()
-	err = json.Unmarshal(responsePayload.GetBody().Value, response)
-	return response, err
+	return rpc_response.InnerResponseJsonUnmarshal(responsePayload.GetBody().Value, responseFunc)
 }
 
 func (g *GrpcConnection) close() {
diff --git a/common/remote/rpc/rpc_response/const.go b/common/remote/rpc/rpc_response/const.go
new file mode 100644
index 0000000..34d0ebc
--- /dev/null
+++ b/common/remote/rpc/rpc_response/const.go
@@ -0,0 +1,10 @@
+package rpc_response
+
+type ResponseCode int
+
+const (
+	ResponseSuccessCode ResponseCode = 200
+	ResponseFailCode    ResponseCode = 500
+
+	ResponseSuccessField = "success"
+)
diff --git a/common/remote/rpc/rpc_response/rpc_response.go b/common/remote/rpc/rpc_response/rpc_response.go
index f41f6ca..2e364af 100644
--- a/common/remote/rpc/rpc_response/rpc_response.go
+++ b/common/remote/rpc/rpc_response/rpc_response.go
@@ -36,6 +36,7 @@ type IResponse interface {
 	GetBody() string
 	GetErrorCode() int
 	IsSuccess() bool
+	SetSuccess(bool)
 	GetResultCode() int
 	GetMessage() string
 }
@@ -60,6 +61,10 @@ func (r *Response) IsSuccess() bool {
 	return r.Success
 }
 
+func (r *Response) SetSuccess(successResult bool) {
+	r.Success = successResult
+}
+
 func (r *Response) GetErrorCode() int {
 	return r.ErrorCode
 }
diff --git a/common/remote/rpc/rpc_response/utils.go b/common/remote/rpc/rpc_response/utils.go
new file mode 100644
index 0000000..1f70ebb
--- /dev/null
+++ b/common/remote/rpc/rpc_response/utils.go
@@ -0,0 +1,24 @@
+package rpc_response
+
+import "encoding/json"
+
+func InnerResponseJsonUnmarshal(responseBody []byte, responseFunc func() IResponse) (IResponse, error) {
+	response := responseFunc()
+	err := json.Unmarshal(responseBody, response)
+	if err != nil {
+		return nil, err
+	}
+
+	if !response.IsSuccess() {
+		tempFiledMap := make(map[string]interface{})
+		err = json.Unmarshal(responseBody, &tempFiledMap)
+		if err != nil {
+			return response, nil
+		}
+		if _, ok := tempFiledMap[ResponseSuccessField]; !ok {
+			response.SetSuccess(response.GetResultCode() == int(ResponseSuccessCode))
+		}
+	}
+	return response, err
+
+}
diff --git a/go.mod b/go.mod
index 064c842..09d8efb 100644
--- a/go.mod
+++ b/go.mod
@@ -40,10 +40,10 @@ require (
 	github.com/prometheus/procfs v0.7.3 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/crypto v0.14.0 // indirect
+	golang.org/x/crypto v0.17.0 // indirect
 	golang.org/x/net v0.17.0 // indirect
-	golang.org/x/sys v0.13.0 // indirect
-	golang.org/x/text v0.13.0 // indirect
+	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/ini.v1 v1.66.2 // indirect
diff --git a/go.sum b/go.sum
index d8dc7a0..a161490 100644
--- a/go.sum
+++ b/go.sum
@@ -249,8 +249,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
+golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -370,8 +370,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -379,8 +379,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=


Test patch:
diff --git a/common/remote/rpc/rpc_response/rpc_response_test.go b/common/remote/rpc/rpc_response/rpc_response_test.go
new file mode 100644
index 0000000..1d4a8c4
--- /dev/null
+++ b/common/remote/rpc/rpc_response/rpc_response_test.go
@@ -0,0 +1,40 @@
+package rpc_response
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestRpcResponseIsSuccess(t *testing.T) {
+	responseBody0 := `{"resultCode":200,"errorCode":0}`
+	responseBody1 := `{"resultCode":200,"errorCode":0,"success":true}`
+	responseBody2 := `{"resultCode":200,"errorCode":0,"success":"true"}`
+	responseBody3 := `{"resultCode":200,"errorCode":0,"success":false}`
+	responseBody4 := `{"resultCode":500,"errorCode":0,"success":true}`
+	responseBody5 := `{"resultCode":500,"errorCode":0,"success":false}`
+
+	responseBodyList := make([]string, 0)
+	responseBodyList = append(responseBodyList, responseBody0, responseBody1, responseBody2, responseBody3, responseBody4, responseBody5)
+	for k, v := range ClientResponseMapping {
+		t.Run("test "+k, func(t *testing.T) {
+			for index, responseBody := range responseBodyList {
+				response, err := InnerResponseJsonUnmarshal([]byte(responseBody), v)
+				switch index {
+				case 0, 1, 4:
+					assert.True(t, response.IsSuccess())
+					break
+				case 3, 5:
+					assert.False(t, response.IsSuccess())
+					break
+				case 2:
+					assert.Nil(t, response)
+					assert.NotNil(t, err)
+					t.Logf("handle %d failed with responseBody: %s", index, responseBody)
+					break
+				default:
+					panic("unknown index")
+				}
+			}
+		})
+	}
+}