Spyne SOAP服务返回JSON而非XML的问题求助
解决Spyne SOAP服务返回JSON而非XML的问题
核心排查方向
你的测试工具能正常接收XML,但客户端收到JSON,说明问题大概率出在客户端请求头、服务端返回类型定义或Spyne协议强制配置上,以下是具体解决方案:
1. 替换AnyDict为强类型的ComplexModel返回定义
使用AnyDict会让Spyne自动推断序列化方式,容易出现格式不一致的问题。你需要定义与请求结构对应的响应模型,强制Spyne生成符合SOAP规范的XML:
from spyne import ComplexModel, Unicode # 定义证书子模型 class CertificateResponse(ComplexModel): Date = Unicode Number = Unicode Blanc = Unicode CountryCode = Unicode ExpirationDate = Unicode Canceled = Unicode IssuePlace = Unicode Inspector = Unicode # 定义完整响应模型 class Response91Type(ComplexModel): GUID = Unicode SendDateTime = Unicode Certificate = CertificateResponse Status = Unicode StatusCode = Unicode Inspector = Unicode # 修改服务方法的返回类型 class RussianIntegrationApiView(ServiceBase): @rpc(Request91Type, _returns=Response91Type, _out_variable_name="Response91") def Request91(ctx, request91type): # 原有逻辑不变,最后返回对应结构的对象或字典 return { "GUID": request91_dict['GUID'] or None, "SendDateTime": request91_dict['SendDateTime'] or None, "Certificate": { "Date": request91_dict['Certificate']['Date'] or None, "Number": request91_dict['Certificate']['Number'] or None, "Blanc": request91_dict['Certificate']['Blanc'] or None, "CountryCode": request91_dict['Certificate']['CountryCode'] or None, "ExpirationDate": request91_dict['Certificate']['ExpirationDate'] or None, "Canceled": request91_dict['Certificate']['Canceled'] or None, "IssuePlace": request91_dict['Certificate']['IssuePlace'] or None, "Inspector": request91_dict['Certificate']['Inspector'] or None, }, "Status": request91_dict['Status'] or None, "StatusCode": request91_dict['StatusCode'] or None, "Inspector": request91_dict['Inspector'] or None, }
2. 强制服务端输出XML,忽略客户端Accept头
确保Spyne的SOAP协议强制返回XML,避免根据客户端请求头自动切换格式:
# 修改Application初始化,明确设置out_protocol的content_type application = Application([RussianIntegrationApiView], 'https://argusgate.fitorf.ru/srv/ws/uz3', name='UZ3SoapBinding', in_protocol=Soap11(validator='soft'), out_protocol=Soap11(content_type='text/xml; charset=utf-8'))
3. 检查客户端请求头配置
让客户端确认以下请求头是否正确设置:
Content-Type: 必须为text/xml; charset=utf-8(SOAP 1.1)或application/soap+xml; charset=utf-8(SOAP 1.2)Accept: 包含text/xml或application/soap+xml,而非仅application/jsonSOAPAction: 对应服务方法的SOAP动作(可从WSDL中获取)
如果客户端发送的请求头偏向JSON格式,Spyne可能会错误地返回JSON响应。
4. 调试服务端实际输出
在服务端添加日志,确认实际返回的内容和响应头:
# 修改on_method_return_string监听器 def on_method_return_string(ctx, method_return_string): logging.info(f"Response Content-Type: {ctx.out_protocol.content_type}") logging.info(f"Response Body: {method_return_string}") # 或者在dispatcher中添加日志 @csrf_exempt def russian_service_dispatcher(request): if request.get_full_path() in ('/UzGosKarantinWebService/russian/?wsdl', '/UzGosKarantinWebService/russian?wsdl'): return get_wsdl_file_russian(request) # 打印客户端请求头 logging.info(f"Client Accept Header: {request.META.get('HTTP_ACCEPT')}") logging.info(f"Client Content-Type: {request.META.get('CONTENT_TYPE')}") response = russian_api_service(request) # 打印服务端响应头 logging.info(f"Server Response Content-Type: {response['Content-Type']}") return response
通过日志可以明确是服务端确实返回了JSON,还是客户端对XML做了错误解析。
5. 确认WSDL与服务定义一致
检查你提供的russian.wsdl文件,确保其中定义的响应类型与你服务中返回的模型结构完全匹配,客户端可能依赖WSDL的定义来解析响应,如果WSDL定义与实际返回结构不符,可能导致解析错误(比如误以为是JSON)。
内容的提问来源于stack exchange,提问作者Shokhrukh Shodiev
相关产品推荐
相关产品推荐

