带有XML正文和文件作为附件的HTTP POST

I have an issue. I am working on a client in Go which contacts a SOAP server. I am supposed to send an HTTP POST request to the server with SOAP message in the body. And I have to also attach one file with the request. How do I do that?

Till now, I am able to just put SOAP message in the request, but not getting how to include the file as well in the request. Below is a code to generate the request. How do I include the file in this request?

payload := strings.NewReader(soapDataString)

req, _ := http.NewRequest("POST", endPointUrl, payload)

req.SetBasicAuth("user", "password")
req.Header.Add("content-type", "text/xml")
req.Header.Add("cache-control", "no-cache")
req.Header.Add("SOAPAction", "")

return req

Either you should use a SOAP library that supports adding attachment or you should know SOAP standard to include an attachment.

From https://www.w3.org/TR/SOAP-attachments

The following example shows a SOAP 1.1 message with an attached facsimile image of the signed claim form (claim061400a.tiff):

MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
        start="<claim061400a.xml@claiming-it.com>"
Content-Description: This is the optional message description.

--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <claim061400a.xml@claiming-it.com>

<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
..
<theSignedForm href="cid:claim061400a.tiff@claiming-it.com"/>
..
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-ID: <claim061400a.tiff@claiming-it.com>

...binary TIFF image...
--MIME_boundary--

It's a multipart MIME type. You could use mime/multipart package to generate a multipart with ease.

Here is another snippet that creates a multipart form that includes an arbitrary file from file system (from this blog).

file, err := os.Open(path)
if err != nil {
    return nil, err
}
defer file.Close()

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
    return nil, err
}
_, err = io.Copy(part, file)

err = writer.Close()
if err != nil {
    return nil, err
}

req, err := http.NewRequest("POST", uri, body)
req.Header.Set("Content-Type", writer.FormDataContentType())
return req, err