Поддержка WSDL/SOAP на Go?

Существуют ли пакеты для поддержки SOAP/WSDL на Go?


person venkyk    schedule 01.08.2012    source источник
comment
Спасибо за небольшой пакет XML/SOAP, хорошо справился со своей задачей. Ребята могут найти библиотеку здесь -- github.com/webconnex/xmlutil   -  person Knights    schedule 10.09.2015
comment
Мне часто приходится использовать SOAP в устаревших системах, и до прошлых выходных я делал это с помощью структур жесткого кодирования в Go. Взломал парсер + генератор кода Go для WSDL, который может создавать пригодный для использования код Go для вызова SOAP. Некоторые из API, которые я использую, довольно обширны и генерируют файлы с более чем 2k LOC. Проверьте это: github.com/fiorix/wsdl2go   -  person fiorix    schedule 22.03.2016


Ответы (5)


Неа.

SOAP отстой, но мне пришлось реализовать сервер уже определенного протокола, который использует SOAP, поэтому я слушал с net/http и декодировал/кодировал конверты с encoding/xml. Через несколько минут я уже отправил свой первый конверт с Go.

person Zippo    schedule 01.08.2012
comment
Конечно поддерживает, но существует бесконечное множество корпоративных систем, поддерживающих только SOAP. Для этих случаев нам все еще нужно что-то полезное. - person fiorix; 22.03.2016

В 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"`
}

И вы строите это так:

MethodCall{
    XSI{"xsd:string", "One"},
    XSI{"xsd:string", "Two"},
}

Что дает вам:

<MethodCall>
    <One xsi:type="xsd:string">One</One>
    <Two xsi:type="xsd:string">Two</Two>
</MethodCall>

Теперь это может быть нормально. Это, безусловно, выполняет свою работу. Но что, если вам нужно больше, чем просто string? encoding/xml в настоящее время не поддерживает interface{}.

Как видите, это усложняется. Если бы у вас был один SOAP API для интеграции, это, вероятно, было бы не так уж плохо. А если бы их было несколько, и у каждого были бы свои особенности?

Было бы неплохо, если бы вы могли просто сделать это?

type MethodCall struct {
    One string
    Two string
}

Затем скажите 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)
}

В приведенном выше примере я использую метод 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)

Вы найдете метод 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>

Это DiffGram, часть Microsoft .NET. Вы можете использовать метод Find, чтобы добраться до Table1. Методы Decode и DecodeElement также работают со срезами. Таким образом, вы можете передать []MethodCallResponse, если NewDataSet содержит более одного результата.

Я согласен с Zippower, что SOAP — отстой. Но, к сожалению, многие предприятия используют SOAP, и вам иногда приходится использовать эти API. С пакетом xmlutil я надеюсь сделать работу с ним немного менее болезненной.

person Luke    schedule 13.07.2013
comment
Совет Go теперь поддерживает Marsalers и Unmarshalers в кодировке/xml, как это уже было в кодировке/json, и ожидается, что эта функция будет в Go 1.2. Это может помочь в обработке SOAP. - person Matt; 04.09.2013
comment
Отлично работает @luke, вашей небольшой утилите xml lib...js нужна документация по началу работы, хотя за несколько минут сканирования с помощью приведенного выше сценария я смог понять, как действовать. - person Knights; 10.09.2015
comment
Я написал анализатор WSDL, который может генерировать код Go для вызова SOAP. В кодировке/xml есть много ограничений в отношении тегов, и я поместил ссылку на это в README. Проверьте это: github.com/fiorix/wsdl2go - person fiorix; 22.03.2016

Хотя в самом Go еще ничего нет, есть gowsdl. Пока мне кажется, что он работает достаточно хорошо, чтобы взаимодействовать с несколькими службами SOAP.

Я не использую предоставляемый им прокси-сервер SOAP, который, по моему мнению, не поддерживает аутентификацию, но gowsdl генерирует из WSDL нужные мне структуры и код для маршалинга запросов и демаршалирования ответов — большая победа.

person Community    schedule 02.04.2015

Существует также wsdl-go.
Но я не использовал его, поэтому я действительно не могу сказать.

person Stefan Steiger    schedule 16.09.2015
comment
Кажется, этого больше не существует. - person Quentin Skousen; 02.02.2018

один из вариантов — использовать gsoap, который создает клиент C WSDL, а затем использовать этот клиент через GO с cgo

person Edoardo    schedule 11.03.2015
comment
Я бы пересмотрела лучший вариант! Это сложный и запутанный подход - person Arman; 16.01.2018
comment
gsoap, вероятно, является наиболее стабильной и полной доступной реализацией мыла: если вы можете решить проблему использования C / C ++ из Go ... тогда это путь к Go :) без каламбура - person Edoardo; 16.01.2018
comment
Имея дело с gSoap из C++, я бы настоятельно не рекомендовал этого делать. Код gSoap — один из худших кодов, которые я когда-либо видел (включая код от поставщиков оборудования!). Это более чем ужасно. Не используйте его. Всякий раз, когда вы сталкиваетесь с выбором, где одним из вариантов является gSoap, выберите другой вариант. Даже если этот вариант «напишите свой собственный». - person Kristof Provost; 25.06.2018
comment
@eddyce Я совершенно серьезно. Я бы посоветовал вам взглянуть на код, но вы кажетесь хорошим человеком, так что не делайте этого с собой. Одним из примеров проблем с gsoap является то, что он вообще не разделяет свой код на слои. В библиотеке мыла я ожидаю увидеть слой для http, один для xml и один для мыла (или внешние библиотеки для обработки этого). gsoap смешивает все это. Наслоения нет. - person Kristof Provost; 25.06.2018
comment
@KristofProvost Я никогда этого не делаю (посмотрите на код, который я имею в виду). предполагается, что клиент wsdl создает работающий код, он не должен быть красивым или читаемым, потому что я даже никогда не открою его. Я отбросил лучший вариант в своем ответе, потому что вы не одиноки, так думаете, с другой стороны, я видел, как gsoap выходит с хорошим интерфейсом на довольно сложных wsdl, и я бы использовал его снова, если бы мне пришлось. - person Edoardo; 25.06.2018