如何在SOAP XML Payload中正确传递字节格式的objectZippedData?
解决SOAP请求中objectZippedData字段格式冲突问题
问题背景
我尝试向SOAP接口传入XML payload,其中objectZippedData字段要求必须为字节格式,但遇到两个矛盾问题:
- 传入字符串格式的编码值时,请求执行失败
- 直接传入字节格式数据时,触发Python错误:
TypeError: can only concatenate str (not "bytes") to str
相关代码如下:
def getSoapResponse(Envelope, url, action): try: envelope = Envelope # Create and register opener. Requires proxy when behind a firewall opener = urllib.request.build_opener(urllib.request.HTTPHandler(), urllib.request.HTTPSHandler(), urllib.request.ProxyHandler()) urllib.request.install_opener(opener) # Create request for the service call request = urllib.request.Request(url) # Configure the request content type to be xml request.add_header("Content-Type", 'application/soap+xml;charset=utf-8') # Set the SOAP action to be invoked; while the call works without this, the value is expected to be set based on standards request.add_header("SOAPAction", action) # Write the xml payload to the request request.data = envelope.encode() handle = urllib.request.urlopen(request, cafile=certifi.where()) # Get the response and process it xmlString = (handle.read(2000).decode('utf-8')) if action != "uploadObjectInSession": # Convert the response into XML tree structure sessionxml = fromstring(xmlString) # Get the session value from the XML tree ReturnVal = sessionxml[0][0][0].text if action == 'login' else 'Success' return (ReturnVal) else: return "Success" except Exception as err: print("getSoapResponse - Error occurred; Message ", str(err)) print("===============================================================") return "Error" def uploadSession(catFile, Target): try: with open(catFile, 'rb') as f: bytes_encoded = base64.b64encode(f.read()) string_encoded = bytes_encoded.decode() f.close() except IOError: return "Error" new_Envelope = """<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://xmlns.oracle.com/oxp/service/v2"> <soapenv:Header/> <soapenv:Body> <v2:uploadObjectInSession> <v2:reportObjectAbsolutePathURL>""" + Target + """</v2:reportObjectAbsolutePathURL> <v2:objectType>xdoz</v2:objectType> <v2:objectZippedData>""" + string_encoded + """</v2:objectZippedData> <v2:bipSessionToken>""" + target_sessionid + """</v2:bipSessionToken> </v2:uploadObjectInSession> </soapenv:Body> </soapenv:Envelope> """ Final = getSoapResponse(Envelope=new_Envelope, url, action='uploadObjectInSession') if Final=="Error": print("FAILURE") return "Error" else: print(Final) return "Success"
触发的错误信息:
new_Envelope = """<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://xmlns.oracle.com/oxp/service/v2"> TypeError: can only concatenate str (not "bytes") to str
核心问题分析
- 函数返回值缺失:
uploadSession函数生成了base64编码字符串string_encoded,但未返回该值,导致后续XML拼接时变量值异常或未定义。 - XML格式限制:XML是纯文本格式,无法直接嵌入字节数据,服务端要求的"字节格式"实际是指经过base64编码的字符串(服务端接收后会自行解码为字节)。
- 字符串拼接风险:直接用字符串拼接构建XML,容易出现特殊字符未转义的问题,破坏XML结构导致请求失败。
具体修复步骤
1. 修复uploadSession函数,返回正确编码值
import base64 def uploadSession(catFile): try: with open(catFile, 'rb') as f: # 读取文件字节并做base64编码,再转成UTF-8字符串 bytes_encoded = base64.b64encode(f.read()) return bytes_encoded.decode('utf-8') except IOError: return "Error"
注:移除了未使用的Target参数,让函数专注于文件编码逻辑。
2. 使用XML库构建payload,避免转义问题
推荐用xml.etree.ElementTree构建XML,自动处理特殊字符转义,确保XML结构合法:
import xml.etree.ElementTree as ET # 调用uploadSession获取编码后的字符串 string_encoded = uploadSession(catFile) if string_encoded == "Error": print("文件读取或编码失败") exit() # 注册XML命名空间 soapenv = "http://schemas.xmlsoap.org/soap/envelope/" v2 = "http://xmlns.oracle.com/oxp/service/v2" ET.register_namespace('soapenv', soapenv) ET.register_namespace('v2', v2) # 逐层构建XML结构 envelope = ET.Element(f"{{{soapenv}}}Envelope") ET.SubElement(envelope, f"{{{soapenv}}}Header") body = ET.SubElement(envelope, f"{{{soapenv}}}Body") upload_obj = ET.SubElement(body, f"{{{v2}}}uploadObjectInSession") # 添加各个字段 ET.SubElement(upload_obj, f"{{{v2}}}reportObjectAbsolutePathURL").text = Target ET.SubElement(upload_obj, f"{{{v2}}}objectType").text = "xdoz" ET.SubElement(upload_obj, f"{{{v2}}}objectZippedData").text = string_encoded ET.SubElement(upload_obj, f"{{{v2}}}bipSessionToken").text = target_sessionid # 转换为XML字符串 new_Envelope = ET.tostring(envelope, encoding='utf-8', method='xml').decode('utf-8')
3. 修正getSoapResponse调用参数
确保调用时参数顺序和格式正确:
Final = getSoapResponse(Envelope=new_Envelope, url=your_service_url, action='uploadObjectInSession') if Final == "Error": print("FAILURE") else: print(Final)
注:替换your_service_url为实际的SOAP接口地址。
验证逻辑
当前getSoapResponse函数中request.data = envelope.encode()是正确的,它会把XML字符串转成UTF-8字节发送给服务端,符合application/soap+xml的请求格式要求。
内容的提问来源于stack exchange,提问作者vow7779
相关产品推荐
相关产品推荐

