使用 Golang 调用 SOAP
Calling SOAP with Golang
我是 golang 的新手,正在尝试使用 gowsdl 进行肥皂调用。
我已经生成了 wsdl 代码并将其安装为一个包。然而,我正在努力理解从中调用方法的语法。
当我检查包装时,这就是我想要的皂体:
type AccountUser struct {
XMLName xml.Name `xml:"http://exacttarget.com/wsdl/partnerAPI AccountUser"`
*APIObject
AccountUserID int32 `xml:"AccountUserID,omitempty"`
UserID string `xml:"UserID,omitempty"`
Password string `xml:"Password,omitempty"`
Name string `xml:"Name,omitempty"`
Email string `xml:"Email,omitempty"`
MustChangePassword bool `xml:"MustChangePassword,omitempty"`
ActiveFlag bool `xml:"ActiveFlag,omitempty"`
ChallengePhrase string `xml:"ChallengePhrase,omitempty"`
ChallengeAnswer string `xml:"ChallengeAnswer,omitempty"`
UserPermissions []*UserAccess `xml:"UserPermissions,omitempty"`
Delete int32 `xml:"Delete,omitempty"`
LastSuccessfulLogin time.Time `xml:"LastSuccessfulLogin,omitempty"`
IsAPIUser bool `xml:"IsAPIUser,omitempty"`
NotificationEmailAddress string `xml:"NotificationEmailAddress,omitempty"`
IsLocked bool `xml:"IsLocked,omitempty"`
Unlock bool `xml:"Unlock,omitempty"`
BusinessUnit int32 `xml:"BusinessUnit,omitempty"`
DefaultBusinessUnit int32 `xml:"DefaultBusinessUnit,omitempty"`
DefaultApplication string `xml:"DefaultApplication,omitempty"`
Locale *Locale `xml:"Locale,omitempty"`
TimeZone *TimeZone `xml:"TimeZone,omitempty"`
DefaultBusinessUnitObject *BusinessUnit `xml:"DefaultBusinessUnitObject,omitempty"`
AssociatedBusinessUnits struct {
BusinessUnit []*BusinessUnit `xml:"BusinessUnit,omitempty"`
} `xml:"AssociatedBusinessUnits,omitempty"`
Roles struct {
Role []*Role `xml:"Role,omitempty"`
} `xml:"Roles,omitempty"`
LanguageLocale *Locale `xml:"LanguageLocale,omitempty"`
SsoIdentities struct {
SsoIdentity []*SsoIdentity `xml:"SsoIdentity,omitempty"`
} `xml:"SsoIdentities,omitempty"`
}
调用 SOAP 的方法是:
func (s *SOAPClient) Call(soapAction string, request, response interface{}) error {
envelope := SOAPEnvelope{
//Header: SoapHeader{},
}
envelope.Body.Content = request
buffer := new(bytes.Buffer)
encoder := xml.NewEncoder(buffer)
//encoder.Indent(" ", " ")
if err := encoder.Encode(envelope); err != nil {
return err
}
if err := encoder.Flush(); err != nil {
return err
}
log.Println(buffer.String())
req, err := http.NewRequest("POST", s.url, buffer)
if err != nil {
return err
}
if s.auth != nil {
req.SetBasicAuth(s.auth.Login, s.auth.Password)
}
req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"")
if soapAction != "" {
req.Header.Add("SOAPAction", soapAction)
}
req.Header.Set("User-Agent", "gowsdl/0.1")
req.Close = true
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: s.tls,
},
Dial: dialTimeout,
}
client := &http.Client{Transport: tr}
res, err := client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
rawbody, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if len(rawbody) == 0 {
log.Println("empty response")
return nil
}
log.Println(string(rawbody))
respEnvelope := new(SOAPEnvelope)
respEnvelope.Body = SOAPBody{Content: response}
err = xml.Unmarshal(rawbody, respEnvelope)
if err != nil {
return err
}
fault := respEnvelope.Body.Fault
if fault != nil {
return fault
}
return nil
}
我已经将包导入到我的 go 文件中,希望得到有关如何调用它的指导。
要使用生成的代码,您显然必须首先使用生成的 "constructor" 函数之一初始化 soap 客户端 NewSOAPClient
或 NewSOAPClientWithTLSConfig
.
之后您需要准备两个值,您可以将它们用作Call
方法的请求和响应参数,它们代表soap request/response 有效载荷。
这两个值的类型将取决于您要进行的调用类型,例如假设的调用 create_account、update_account 和 delete_account 通常需要不同的类型。基本上,request
值的类型应该是 可编组 到一个 xml 中,该 xml 与 soap 服务为指定操作期望的 xml 相匹配, response
的类型应该是 unmarshalable 来自 xml 匹配 soap 服务对指定操作的记录响应。
考虑这个人为的例子:
有一个允许您创建用户的 SOAP 服务。为了能够使用该服务创建用户,它需要您发送电子邮件和密码,如果一切正常,它将 return 一个 ID。在这种情况下,您的两个 request/response 类型将如下所示:
type CreateUserRequest struct {
Email string `xml:"Email,omitempty"`
Password string `xml:"Password,omitempty"`
}
type CreateUserResponse struct {
ID string `xml:"ID"`
}
那么客户端代码将如下所示:
client := NewSOAPClient("https://soap.example.com/call", true, nil)
req := &CreateUserRequest{
Email: "jdoe@example.com",
Password: "1234567890",
}
res := &CreateUserResponse{}
if err := client.Call("create_user", req, res); err != nil {
panic(err)
}
// if everything went well res.ID should have its
// value set with the one returned by the service.
fmt.Println(res.ID)
我是 golang 的新手,正在尝试使用 gowsdl 进行肥皂调用。
我已经生成了 wsdl 代码并将其安装为一个包。然而,我正在努力理解从中调用方法的语法。
当我检查包装时,这就是我想要的皂体:
type AccountUser struct {
XMLName xml.Name `xml:"http://exacttarget.com/wsdl/partnerAPI AccountUser"`
*APIObject
AccountUserID int32 `xml:"AccountUserID,omitempty"`
UserID string `xml:"UserID,omitempty"`
Password string `xml:"Password,omitempty"`
Name string `xml:"Name,omitempty"`
Email string `xml:"Email,omitempty"`
MustChangePassword bool `xml:"MustChangePassword,omitempty"`
ActiveFlag bool `xml:"ActiveFlag,omitempty"`
ChallengePhrase string `xml:"ChallengePhrase,omitempty"`
ChallengeAnswer string `xml:"ChallengeAnswer,omitempty"`
UserPermissions []*UserAccess `xml:"UserPermissions,omitempty"`
Delete int32 `xml:"Delete,omitempty"`
LastSuccessfulLogin time.Time `xml:"LastSuccessfulLogin,omitempty"`
IsAPIUser bool `xml:"IsAPIUser,omitempty"`
NotificationEmailAddress string `xml:"NotificationEmailAddress,omitempty"`
IsLocked bool `xml:"IsLocked,omitempty"`
Unlock bool `xml:"Unlock,omitempty"`
BusinessUnit int32 `xml:"BusinessUnit,omitempty"`
DefaultBusinessUnit int32 `xml:"DefaultBusinessUnit,omitempty"`
DefaultApplication string `xml:"DefaultApplication,omitempty"`
Locale *Locale `xml:"Locale,omitempty"`
TimeZone *TimeZone `xml:"TimeZone,omitempty"`
DefaultBusinessUnitObject *BusinessUnit `xml:"DefaultBusinessUnitObject,omitempty"`
AssociatedBusinessUnits struct {
BusinessUnit []*BusinessUnit `xml:"BusinessUnit,omitempty"`
} `xml:"AssociatedBusinessUnits,omitempty"`
Roles struct {
Role []*Role `xml:"Role,omitempty"`
} `xml:"Roles,omitempty"`
LanguageLocale *Locale `xml:"LanguageLocale,omitempty"`
SsoIdentities struct {
SsoIdentity []*SsoIdentity `xml:"SsoIdentity,omitempty"`
} `xml:"SsoIdentities,omitempty"`
}
调用 SOAP 的方法是:
func (s *SOAPClient) Call(soapAction string, request, response interface{}) error {
envelope := SOAPEnvelope{
//Header: SoapHeader{},
}
envelope.Body.Content = request
buffer := new(bytes.Buffer)
encoder := xml.NewEncoder(buffer)
//encoder.Indent(" ", " ")
if err := encoder.Encode(envelope); err != nil {
return err
}
if err := encoder.Flush(); err != nil {
return err
}
log.Println(buffer.String())
req, err := http.NewRequest("POST", s.url, buffer)
if err != nil {
return err
}
if s.auth != nil {
req.SetBasicAuth(s.auth.Login, s.auth.Password)
}
req.Header.Add("Content-Type", "text/xml; charset=\"utf-8\"")
if soapAction != "" {
req.Header.Add("SOAPAction", soapAction)
}
req.Header.Set("User-Agent", "gowsdl/0.1")
req.Close = true
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: s.tls,
},
Dial: dialTimeout,
}
client := &http.Client{Transport: tr}
res, err := client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
rawbody, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if len(rawbody) == 0 {
log.Println("empty response")
return nil
}
log.Println(string(rawbody))
respEnvelope := new(SOAPEnvelope)
respEnvelope.Body = SOAPBody{Content: response}
err = xml.Unmarshal(rawbody, respEnvelope)
if err != nil {
return err
}
fault := respEnvelope.Body.Fault
if fault != nil {
return fault
}
return nil
}
我已经将包导入到我的 go 文件中,希望得到有关如何调用它的指导。
要使用生成的代码,您显然必须首先使用生成的 "constructor" 函数之一初始化 soap 客户端 NewSOAPClient
或 NewSOAPClientWithTLSConfig
.
之后您需要准备两个值,您可以将它们用作Call
方法的请求和响应参数,它们代表soap request/response 有效载荷。
这两个值的类型将取决于您要进行的调用类型,例如假设的调用 create_account、update_account 和 delete_account 通常需要不同的类型。基本上,request
值的类型应该是 可编组 到一个 xml 中,该 xml 与 soap 服务为指定操作期望的 xml 相匹配, response
的类型应该是 unmarshalable 来自 xml 匹配 soap 服务对指定操作的记录响应。
考虑这个人为的例子:
有一个允许您创建用户的 SOAP 服务。为了能够使用该服务创建用户,它需要您发送电子邮件和密码,如果一切正常,它将 return 一个 ID。在这种情况下,您的两个 request/response 类型将如下所示:
type CreateUserRequest struct {
Email string `xml:"Email,omitempty"`
Password string `xml:"Password,omitempty"`
}
type CreateUserResponse struct {
ID string `xml:"ID"`
}
那么客户端代码将如下所示:
client := NewSOAPClient("https://soap.example.com/call", true, nil)
req := &CreateUserRequest{
Email: "jdoe@example.com",
Password: "1234567890",
}
res := &CreateUserResponse{}
if err := client.Call("create_user", req, res); err != nil {
panic(err)
}
// if everything went well res.ID should have its
// value set with the one returned by the service.
fmt.Println(res.ID)