如何处理SOAP with Attachments (SwA)中的XML上传

SwA上传失败主因是Content-Type配置错误:必须用multipart/related包装,主XML部分Content-Type须为text/xml或application/soap+xml,且start-info参数需显式指定,各part的Content-ID须含尖括号并严格匹配SOAP中cid引用。

SwA上传失败时常见的Content-Type错误

SwA不是普通XML POST,必须用multipart/related包装,且主XML部分的Content-Type必须是text/xmlapplication/soap+xml,不能是application/xml。常见错误是直接把SOAP XML当纯文本POST,导致服务端解析出Invalid MIME structureMissing start-info parameter

  • start-info参数必须显式指定,例如:Content-Type: multipart/related; type="text/xml"; start=""; boundary="uuid:12345"
  • 每个part需带Content-ID头,格式为(尖括号不可省略)
  • 附件part的Content-Transfer-Encoding建议用base64,避免二进制乱码

Python中用requests构造SwA请求的关键步骤

标准requests.post()不支持原生SwA,需手动拼接multipart body。核心是控制boundary、start-info和各part的headers顺序。

import requests

soap_xml = '''

  
    
      
    
  
'''

with open("report.pdf", "rb") as f:
    pdf_data = f.read()

boundary = "uuid:abc123"
start = ""

body = (
    f"--{boundary}\r\n"
    'Content-Type: text/xml; charset=utf-8\r\n'
    f'Content-Transfer-Encoding: 8bit\r\n'
    f'Content-ID: {start}\r\n\r\n'
    f"{soap_xml}\r\n"
    f"--{boundary}\r\n"
    'Content-Type: application/pdf\r\n'
    'Content-Transfer-Encoding: base64\r\n'
    'Content-ID: \r\n\r\n'
    + base64.b64encode(pdf_data).decode() + "\r\n"
    f"--{boundary}--\r\n"
)

headers = {
    "Content-Type": f'multipart/related; type="text/xml"; start="{start}"; boundary="{boundary}"',
    "SOAPAction": '"http://example.com/UploadDocument"'
}

response = requests.post("https://api.example.com/soap", headers=headers, data=body)

Java(Apache Axis2)里AttachmentUtils的典型误用

Axis2自带org.apache.axis2.attachments.Attachments,但很多人直接传入FileDataSource而忽略Content-ID一致性。关键点在于:SOAP body中引用的cid:必须与附件part的Content-ID完全匹配(包括大小写和空格)。

  • 不要用new DataHandler(new FileDataSource("x.pdf"))后直接addAttachment()——它会自动生成随机Content-ID,无法与SOAP中硬编码的对齐
  • 正确做法是先创建javax.activation.DataHandler,再调用setContentType("application/pdf")setContentID("")
  • Axis2默认启用SwA,但若服务端返回HTTP 415 Unsupported Media Type,检查是否启用了messageBuilder配置:application/soap+xml对应org.apache.axis2.builder.SOAPBuilder

调试SwA请求时必须检查的三个原始响应头

服务端拒绝SwA请求时,HTTP状态码往往掩盖了真实问题。真正线索藏在响应头里:

  • Content-Type是否返回multipart/related?如果不是,说明服务端未识别SwA,可能因start-info缺失或boundary不匹配
  • X-SOAP-Error(某些厂商自定义头)常含Invalid attachment reference: cid:xxx,意味着SOAP body里的cid:没在附件part中找到对应Content-ID
  • Connectionclose且无Content-Length,大概率是multipart body末尾少了一个--{boundary}--,导致服务端等待更多数据超时

SwA的麻烦不在

逻辑,而在每个header字段的字面精确性——少一个尖括号、多一个空格、大小写错位,都会让整个请求静默失败。