2012-08-01 34 views
16

Tôi nhìn xung quanh và tất cả những gì tôi có thể tìm thấy là sự hỗ trợ cho xml.Hỗ trợ WSDL/SOAP trên Go?

Có gói nào hỗ trợ SOAP/WSDL trên Go không?

+0

Cảm ơn gói XML/SOAP nhỏ, đã thực hiện tốt công việc. Các bạn có thể tìm thấy thư viện ở đây - https://github.com/webconnex/xmlutil – Knights

+0

Tôi thường phải sử dụng SOAP trên các hệ thống cũ và đã thực hiện nó bằng các cấu trúc mã hóa cứng trong Go cho đến cuối tuần trước. Đã khởi động trình phân tích cú pháp + Trình tạo mã Go cho WSDL có thể tạo mã Go có thể sử dụng để gọi SOAP. Một số API tôi sử dụng khá rộng, tạo ra các tệp có hơn 2k LOC. Hãy khám phá: https://github.com/fiorix/wsdl2go – fiorix

Trả lời

11

Không.

SOAP hút, nhưng tôi phải triển khai máy chủ của giao thức đã được xác định sử dụng SOAP, vì vậy tôi đã nghe net/http và phong bì được mã hóa/mã hóa với encoding/xml. Trong vài phút, tôi đã phục vụ phong bì đầu tiên của mình với Go.

+1

Chắc chắn, nhưng có vô số hệ thống doanh nghiệp chỉ hỗ trợ SOAP. Đối với những trường hợp đó, chúng tôi vẫn cần một cái gì đó hữu ích. – fiorix

17

Không có hỗ trợ cho WSDL trong Go. Hỗ trợ trong các ngôn ngữ khác là tĩnh hoặc động: Một trong hai cấu trúc được tạo trước từ WSDL, hoặc nó được thực hiện ngay lập tức với các bảng băm.

Tuy nhiên, bạn có thể mã hóa và giải mã các yêu cầu SOAP theo cách thủ công. Tôi thấy rằng gói tiêu chuẩn encoding/xml không đủ cho SOAP. Có rất nhiều quirks trong các máy chủ khác nhau, và những hạn chế trong encoding/xml làm cho nó khó khăn tạo ra một yêu cầu các máy chủ này hài lòng với.

Ví dụ: một số máy chủ cần xsi:type="xsd:string" trên mọi thẻ chuỗi. Để làm điều này đúng struct của bạn cần phải trông như thế này cho encoding/xml:

type MethodCall struct { 
    One XSI 
    Two XSI 
} 

type XSI struct { 
    Type string `xml:"xsi:type,attr"` 
    Vaue string `xml:",chardata"` 
} 

Và bạn xây dựng nó như thế này:

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

nào mang đến cho bạn:

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

Bây giờ này có thể là ok. Nó chắc chắn sẽ hoàn thành công việc. Nhưng nếu bạn cần nhiều hơn chỉ một số string thì sao? encoding/xml hiện không hỗ trợ interface{}.

Như bạn thấy điều này trở nên phức tạp. Nếu bạn có một API SOAP để tích hợp, điều này có thể sẽ không quá tệ. Điều gì sẽ xảy ra nếu bạn có nhiều người, mỗi người đều có những điều kỳ quặc riêng của họ?

Nó sẽ không được tốt đẹp nếu bạn chỉ có thể làm điều này?

type MethodCall struct { 
    One string 
    Two string 
} 

Sau đó nói đến encoding/xml: "Máy chủ này muốn loại xsi".

Để giải quyết vấn đề này, tôi đã tạo github.com/webconnex/xmlutil. Đó là một công việc đang tiến hành. Nó không có tất cả các tính năng của bộ mã hóa/giải mã của encoding/xml, nhưng nó có những gì cần thiết cho SOAP.

Dưới đây là một ví dụ làm việc:

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) 
} 

Với ví dụ trên tôi sử dụng phương pháp Find để có được những đối tượng phản ứng, hoặc một lỗi. Điều này là không cần thiết. Bạn cũng có thể làm điều đó như thế này:

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) 

Bạn sẽ tìm thấy phương pháp Find hữu ích khi dữ liệu của bạn trông như thế này:

<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> 

Đây là một DiffGram, một phần của Microsoft .NET.Bạn có thể sử dụng phương thức Find để truy cập Table1. Phương pháp DecodeDecodeElement cũng hoạt động trên các lát cắt. Vì vậy, bạn có thể vượt qua trong một []MethodCallResponse nếu NewDataSet xảy ra có chứa nhiều hơn một kết quả.

Tôi đồng ý với Zippower rằng SOAP không hút. Nhưng tiếc là rất nhiều doanh nghiệp sử dụng SOAP và đôi khi bạn buộc phải sử dụng các API này. Với gói xmlutil tôi hy vọng sẽ làm cho nó ít đau đớn hơn một chút.

+6

Mẹo đi bây giờ hỗ trợ [Marsalers] (http://tip.golang.org/pkg/encoding/xml/#Marshaler) và [Unmarshalers] (http://tip.golang.org/pkg/encoding/xml/# Unmarshaler) trong mã hóa/xml như mã hóa/json đã làm, và tính năng này dự kiến ​​sẽ được trong Go 1.2. Điều này có thể giúp xử lý SOAP. – Matt

+0

Hoạt động tuyệt vời @ luke, lib tiện ích xml nhỏ của bạn ... js cần một tài liệu bắt đầu, mặc dù với vài phút quét qua kịch bản ở trên, tôi đã có thể hiểu cách thực hiện mọi thứ – Knights

+0

Tôi đã viết một trình phân tích cú pháp WSDL có thể tạo mã Go để gọi SOAP. Có rất nhiều hạn chế trong mã hóa/xml liên quan đến thẻ, và tôi đặt một liên kết đến đó trong README. Hãy khám phá: https://github.com/fiorix/wsdl2go – fiorix

-1

Lựa chọn tốt nhất là sử dụng gsoap trong đó sản xuất một khách hàng C WSDL và sau đó sử dụng khách hàng thông qua GO với cgo

+1

Tôi sẽ xem xét lại "Tùy chọn tốt nhất"! Đó là một cách tiếp cận phức tạp và khó hiểu – Arman

+0

gsoap có lẽ là sự triển khai xà phòng ổn định và hoàn thiện nhất: nếu bạn có thể giải quyết những rắc rối khi sử dụng C/C++ từ Go ... thì cách của nó để Go :) không có ý định chơi chữ – eddyce

5

Trong khi vẫn còn có gì trong Go chính nó, có gowsdl. Cho đến nay, có vẻ như tôi đã làm việc đủ tốt để giao tiếp với một số dịch vụ SOAP.

Tôi không sử dụng proxy SOAP mà nó cung cấp, mà tôi tin là không hỗ trợ auth, nhưng gowsdl tạo cấu trúc và mã tôi cần từ WSDL cho các yêu cầu sắp xếp và phản hồi không chính thức - một chiến thắng lớn.

0

Ngoài ra còn có wsdl-go.
Nhưng tôi đã không sử dụng nó, vì vậy tôi thực sự không thể nói.

+0

dường như không còn tồn tại. –