如何移除Spyne库生成的SOAP请求中的e:前缀?
问题描述
我使用Spyne库构建了如下SOAP服务代码:
from spyne.application import Application from spyne.decorator import rpc from spyne.model.complex import ComplexModel from spyne.model.primitive import String, Integer from spyne.service import ServiceBase from spyne.protocol.soap import Soap11 from spyne.server.django import DjangoApplication from spyne import Unicode from django.views.decorators.csrf import csrf_exempt from lxml import etree class StatusData(ComplexModel): date = String class AppealsExternalStatusRequest(ComplexModel): messageId = String class DataWrapper(ComplexModel): AppealsExternalStatusRequest = AppealsExternalStatusRequest class AppealsService(ServiceBase): @rpc(DataWrapper, _returns=String, _body_style='bare', _operation_name='data') def receive_status(ctx, data_wrapper): print(data_wrapper) return "Received" soap_app = Application([AppealsService], tns='certain_path', in_protocol=Soap11(validator='lxml'), out_protocol=Soap11()) django_soap_app = DjangoApplication(soap_app) django_soap_app = csrf_exempt(django_soap_app)
访问http://localhost/soap_api?wsdl得到的请求格式如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="path" xmlns:e="app.soap_service"> <soapenv:Header/> <soapenv:Body> <v1:data> <e:AppealsExternalStatusRequest> <!--Optional:--> <e:messageId>?</e:messageId> <e:statusData> <!--Optional:--> <e:date>?</e:date> <!--Optional:--> </e:statusData> </e:AppealsExternalStatusRequest> </v1:data> </soapenv:Body> </soapenv:Envelope>
我希望移除其中的e:前缀,但尝试添加命名空间会生成其他前缀,移除命名空间则会自动出现e:前缀。Spyne会自动生成xmlns:e="app.soap_service"(对应app_name.file_name),导致所有namespace=None的字段都带有e:前缀,请问该如何解决这个问题?
解决方案
Spyne自动生成额外命名空间前缀的核心原因是:自定义的ComplexModel类默认使用了所在模块的命名空间(即app.soap_service),没有和Application的目标命名空间(tns)保持一致。只需给所有自定义复杂类型指定__namespace__属性,值与Application的tns相同即可解决。
修改后的代码示例
from spyne.application import Application from spyne.decorator import rpc from spyne.model.complex import ComplexModel from spyne.model.primitive import String, Integer from spyne.service import ServiceBase from spyne.protocol.soap import Soap11 from spyne.server.django import DjangoApplication from spyne import Unicode from django.views.decorators.csrf import csrf_exempt from lxml import etree # 统一定义目标命名空间常量,避免重复书写 TARGET_NAMESPACE = 'certain_path' class StatusData(ComplexModel): __namespace__ = TARGET_NAMESPACE date = String class AppealsExternalStatusRequest(ComplexModel): __namespace__ = TARGET_NAMESPACE messageId = String class DataWrapper(ComplexModel): __namespace__ = TARGET_NAMESPACE AppealsExternalStatusRequest = AppealsExternalStatusRequest class AppealsService(ServiceBase): @rpc(DataWrapper, _returns=String, _body_style='bare', _operation_name='data') def receive_status(ctx, data_wrapper): print(data_wrapper) return "Received" soap_app = Application([AppealsService], tns=TARGET_NAMESPACE, in_protocol=Soap11(validator='lxml'), out_protocol=Soap11()) django_soap_app = DjangoApplication(soap_app) django_soap_app = csrf_exempt(django_soap_app)
简化写法(可选)
如果自定义复杂类型较多,可以创建一个基类统一设置命名空间,其他类继承该基类即可:
class BaseComplexModel(ComplexModel): __namespace__ = TARGET_NAMESPACE class StatusData(BaseComplexModel): date = String class AppealsExternalStatusRequest(BaseComplexModel): messageId = String class DataWrapper(BaseComplexModel): AppealsExternalStatusRequest = AppealsExternalStatusRequest
修改后,所有自定义复杂类型会和服务使用同一命名空间,WSDL生成的请求中将不再出现e:前缀,统一使用服务的命名空间前缀(如示例中的v1:,也可通过Soap11(prefix='自定义前缀')指定自定义前缀)。
内容的提问来源于stack exchange,提问作者nope_that_does_not_work
相关产品推荐
相关产品推荐

