从你的代码和错误信息来看,问题很可能出在SOAP请求的格式或参数传递上。gosoap库在处理某些WSDL时可能存在格式兼容性问题。以下是更可靠的实现方案:
package main
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"time"
)
type Envelope struct {
XMLName xml.Name `xml:"soap:Envelope"`
Soap string `xml:"xmlns:soap,attr"`
Xsi string `xml:"xmlns:xsi,attr"`
Xsd string `xml:"xmlns:xsd,attr"`
Body Body
}
type Body struct {
XMLName xml.Name `xml:"soap:Body"`
Query QueryShipment
}
type QueryShipment struct {
XMLName xml.Name `xml:"queryShipment"`
Xmlns string `xml:"xmlns,attr"`
WsUserName string `xml:"wsUserName"`
WsPassword string `xml:"wsPassword"`
WsLanguage string `xml:"wsLanguage"`
Keys string `xml:"keys"`
KeyType int `xml:"keyType"`
AddHistoricalData bool `xml:"addHistoricalData"`
OnlyTracking bool `xml:"onlyTracking"`
}
type Response struct {
XMLName xml.Name `xml:"Envelope"`
Body struct {
QueryShipmentResponse struct {
Result string `xml:"result"`
} `xml:"queryShipmentResponse"`
} `xml:"Body"`
}
func main() {
// 构建SOAP请求
request := Envelope{
Soap: "http://schemas.xmlsoap.org/soap/envelope/",
Xsi: "http://www.w3.org/2001/XMLSchema-instance",
Xsd: "http://www.w3.org/2001/XMLSchema",
Body: Body{
Query: QueryShipment{
Xmlns: "http://yurticikargo.com.tr/ShippingOrderDispatcherServices",
WsUserName: "your_username",
WsPassword: "your_password",
WsLanguage: "TR",
Keys: "cargo_key",
KeyType: 0,
AddHistoricalData: false,
OnlyTracking: false,
},
},
}
// 序列化XML
xmlData, err := xml.MarshalIndent(request, "", " ")
if err != nil {
fmt.Printf("XML Marshal error: %v\n", err)
return
}
// 添加SOAP头部
soapRequest := []byte(xml.Header + string(xmlData))
// 创建HTTP客户端
client := &http.Client{
Timeout: 5 * time.Second,
}
// 发送请求
req, err := http.NewRequest("POST",
"http://webservices.yurticikargo.com:8080/KOPSWebServices/ShippingOrderDispatcherServices",
bytes.NewBuffer(soapRequest))
if err != nil {
fmt.Printf("Request creation error: %v\n", err)
return
}
// 设置必要的HTTP头
req.Header.Set("Content-Type", "text/xml; charset=utf-8")
req.Header.Set("SOAPAction", "queryShipment")
// 执行请求
resp, err := client.Do(req)
if err != nil {
fmt.Printf("HTTP request error: %v\n", err)
return
}
defer resp.Body.Close()
// 读取响应
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Read response error: %v\n", err)
return
}
fmt.Printf("Response Status: %s\n", resp.Status)
fmt.Printf("Response Body:\n%s\n", string(body))
// 解析响应
var response Response
err = xml.Unmarshal(body, &response)
if err != nil {
fmt.Printf("XML Unmarshal error: %v\n", err)
return
}
fmt.Printf("Query Result: %s\n", response.Body.QueryShipmentResponse.Result)
}
如果需要处理更复杂的响应结构,可以这样定义:
type ShippingDeliveryVO struct {
OutFlag string `xml:"outFlag"`
OutResult string `xml:"outResult"`
// 添加其他字段
}
type DetailedResponse struct {
XMLName xml.Name `xml:"Envelope"`
Body struct {
QueryShipmentResponse struct {
ShippingDeliveryVO ShippingDeliveryVO `xml:"ShippingDeliveryVO"`
} `xml:"queryShipmentResponse"`
} `xml:"Body"`
}
func parseDetailedResponse(body []byte) {
var resp DetailedResponse
err := xml.Unmarshal(body, &resp)
if err != nil {
fmt.Printf("Detailed parse error: %v\n", err)
return
}
fmt.Printf("Country: %s\n", resp.Body.QueryShipmentResponse.ShippingDeliveryVO.OutFlag)
fmt.Printf("State: %s\n", resp.Body.QueryShipmentResponse.ShippingDeliveryVO.OutResult)
}
这个实现直接使用标准库的encoding/xml包,确保SOAP请求格式正确,特别是:
- 正确的XML命名空间声明
- 正确的SOAPAction头部
- 符合目标服务期望的XML结构
注意替换代码中的用户名、密码和货物密钥为实际值。如果仍有问题,建议使用Wireshark或tcpdump捕获网络包,对比SOAP UI和Go程序发送的原始请求差异。