Go上的WSDL/SOAP支持?

ven*_*kyk 19 soap soap-client go

在Go上是否有任何支持SOAP/WSDL的包?

Luk*_*uke 18

Go中不支持WSDL.其他语言的支持是静态的或动态的:结构都是从WSDL预先生成的,或者是使用哈希表动态完成的.

但是,您可以手动编码和解码SOAP请求.我发现标准encoding/xml包对SOAP来说是不够的.在不同的服务器中存在很多怪癖,并且encoding/xml使得难以生成这些服务器满意的请求的限制.

例如,某些服务器需要xsi:type="xsd:string"每个字符串标记.为了正确地执行此操作,您的结构需要如下所示encoding/xml:

type MethodCall struct {
    One XSI
    Two XSI
}

type XSI struct {
    Type string `xml:"xsi:type,attr"`
    Vaue string `xml:",chardata"`
}
Run Code Online (Sandbox Code Playgroud)

你构建它像这样:

MethodCall{
    XSI{"xsd:string", "One"},
    XSI{"xsd:string", "Two"},
}
Run Code Online (Sandbox Code Playgroud)

哪个给你:

<MethodCall>
    <One xsi:type="xsd:string">One</One>
    <Two xsi:type="xsd:string">Two</Two>
</MethodCall>
Run Code Online (Sandbox Code Playgroud)

现在这可能没问题.它当然可以完成工作.但是如果你需要的不仅仅是一个string呢?encoding/xml目前不支持interface{}.

如你所见,这变得复杂.如果您要集成一个SOAP API,这可能不会太糟糕.如果你有几个,每个都有他们自己的怪癖怎么办?

如果你能做到这一点不是很好吗?

type MethodCall struct {
    One string
    Two string
}
Run Code Online (Sandbox Code Playgroud)

然后说encoding/xml:"这个服务器想要xsi类型".

为了解决这个问题,我创建了github.com/webconnex/xmlutil.这是一项正在进行中的工作.它没有encoding/xml编码器/解码器的所有功能,但它具有SOAP所需的功能.

这是一个有效的例子:

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
    "github.com/webconnex/xmlutil"
    "log"
    //"net/http"
)

type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

type MethodCall struct {
    One string
    Two string
}

type MethodCallResponse struct {
    Three string
}

func main() {
    x := xmlutil.NewXmlUtil()
    x.RegisterNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi")
    x.RegisterNamespace("http://www.w3.org/2001/XMLSchema", "xsd")
    x.RegisterNamespace("http://www.w3.org/2003/05/soap-envelope", "soap")
    x.RegisterTypeMore(Envelope{}, xml.Name{"http://www.w3.org/2003/05/soap-envelope", ""},
        []xml.Attr{
            xml.Attr{xml.Name{"xmlns", "xsi"}, "http://www.w3.org/2001/XMLSchema-instance"},
            xml.Attr{xml.Name{"xmlns", "xsd"}, "http://www.w3.org/2001/XMLSchema"},
            xml.Attr{xml.Name{"xmlns", "soap"}, "http://www.w3.org/2003/05/soap-envelope"},
        })
    x.RegisterTypeMore("", xml.Name{}, []xml.Attr{
        xml.Attr{xml.Name{"http://www.w3.org/2001/XMLSchema-instance", "type"}, "xsd:string"},
    })

    buf := new(bytes.Buffer)
    buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
    buf.WriteByte('\n')
    enc := x.NewEncoder(buf)
    env := &Envelope{Body{MethodCall{
        One: "one",
        Two: "two",
    }}}
    if err := enc.Encode(env); err != nil {
        log.Fatal(err)
    }
    // Print request
    bs := buf.Bytes()
    bs = bytes.Replace(bs, []byte{'>', '<'}, []byte{'>', '\n', '<'}, -1)
    fmt.Printf("%s\n\n", bs)

    /*
        // Send response, SOAP 1.2, fill in url, namespace, and action
        var r *http.Response
        if r, err = http.Post(url, "application/soap+xml; charset=utf-8; action="+namespace+"/"+action, buf); err != nil {
            return
        }
        dec := x.NewDecoder(r.Body)
    */
    // Decode response
    dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope>
        <soap:Body>
            <MethodCallResponse>
                <Three>three</Three>
            </MethodCallResponse>
        </soap:Body>
    </soap:Envelope>`))
    find := []xml.Name{
        xml.Name{"", "MethodCallResponse"},
        xml.Name{"http://www.w3.org/2003/05/soap-envelope", "Fault"},
    }
    var start *xml.StartElement
    var err error
    if start, err = dec.Find(find); err != nil {
        log.Fatal(err)
    }
    if start.Name.Local == "Fault" {
        log.Fatal("Fault!") // Here you can decode a Soap Fault
    }
    var resp MethodCallResponse
    if err := dec.DecodeElement(&resp, start); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%#v\n\n", resp)
}
Run Code Online (Sandbox Code Playgroud)

通过上面的示例,我使用该Find方法来获取响应对象或故障.这不是绝对必要的.你也可以这样做:

x.RegisterType(MethodCallResponse{})
...
// Decode response
dec := x.NewDecoder(bytes.NewBufferString(`<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
    <soap:Body>
        <MethodCallResponse>
            <Three>three</Three>
        </MethodCallResponse>
    </soap:Body>
</soap:Envelope>`))
var start *xml.StartElement
var resp Envelope
if err := dec.DecodeElement(&resp, start); err != nil {
    log.Fatal(err)
}
fmt.Printf("%#v\n\n", resp)
Run Code Online (Sandbox Code Playgroud)

Find当您的数据如下所示时,您会发现该方法很有用:

<soap:Envelope>
  <soap:Body>
    <MethodResponse>
      <MethodResult>
        <diffgr:diffgram>
          <NewDataSet>
            <Table1 diffgr:id="Table1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
              <Three>three</Three>
            </Table1>
          </NewDataSet>
        </diffgr:diffgram>
      </MethodResult>
    </MethodResponse>
  </soap:Body>
</soap:Envelope>
Run Code Online (Sandbox Code Playgroud)

这是一个DiffGram,是Microsoft .NET的一部分.您可以使用该Find方法进入Table1.该DecodeDecodeElement方法也适用于片.所以你可以传入一个[]MethodCallResponseif NewDataSet恰好包含多个结果.

我同意Zippower认为SOAP确实很糟糕.但不幸的是,许多企业使用SOAP,有时您被迫使用这些API.使用xmlutil包,我希望能够减少使用它的痛苦.

  • Go tip现在支持[Marsalers](http://tip.golang.org/pkg/encoding/xml/#Marshaler)和[Unmarshalers](http://tip.golang.org/pkg/encoding/xml/#Unmarshaler )编码/ xml就像编码/ json已经做过的那样,这个功能应该在Go 1.2中.这可能有助于处理SOAP. (6认同)

Mos*_*vah 12

不.

SOAP很糟糕,但是我必须实现一个使用SOAP的已定义协议的服务器,所以我用它来监听net/http和解码/编码的信封encoding/xml.几分钟后,我已经用Go服了我的第一个信封.

  • 当然可以,但是有一个无限的企业系统只支持SOAP.对于这些情况,我们仍需要一些有用的东西. (3认同)

小智 5

虽然Go本身还没有任何东西,但还是有gowsdl.到目前为止,它似乎足以让我与多个SOAP服务进行交互.

我不使用它提供的SOAP代理,我认为它不支持auth,但是gowsdl从WSDL生成我需要的结构和代码来编组请求和解组响应 - 这是一个巨大的胜利.