如何在Spyne构建的SOAP服务中正确返回空列表(含生成器实现方式)
嗨,Axel!我之前也踩过Spyne返回空列表的坑,咱们一步步来解决你的问题:
你现在遇到两个核心问题:直接返回空列表时客户端收到None,以及用生成器实现时空数据导致服务崩溃,下面分别给出解决方案:
一、直接返回列表:让客户端收到空列表而非None
你当前用_returns=Iterable(Integer)作为返回类型,Spyne默认会把空序列序列化为None(因为Iterable类型允许nil值)。要强制返回空列表,需要把返回类型换成Array(Integer),并明确配置参数告诉Spyne:这个字段可以为空,但不能是null:
from spyne import Array, Integer, rpc, Unicode @rpc(Unicode, Integer, Unicode, Integer, _returns=Array(Integer, min_occurs=0, nillable=False)) def searchMethod(ctx, some, parameters): # 你的业务逻辑,获取数据 data = list(range(0)) # 空列表示例 print("the data:", data) return data
这样配置后,当你返回空列表[]时,Spyne会生成对应的空SOAP数组元素,Zeep客户端就能正确解析为空列表,而非None。
二、生成器实现:避免空数据时服务崩溃
你的生成器代码中,空数据时直接return会触发生成器的StopIteration异常,而Spyne会把这个异常判定为服务错误(也就是你看到的500报错)。
正确的做法是不要在生成器函数里直接return,而是通过生成空迭代内容的方式返回。修改后的代码如下:
from spyne import Iterable, Integer, rpc, Unicode @rpc(Unicode, Integer, Unicode, Integer, _returns=Iterable(Integer)) def searchMethod(ctx, some, parameters): # 你的业务逻辑,获取数据 data = list(range(0)) # 空列表示例 print("the data:", data) if not data: print("returning empty iterable") yield from [] # 生成空迭代内容,替代直接return else: print("iterating") for item in data: yield item
更简洁的写法可以直接用yield from覆盖所有情况,不管数据是否为空:
@rpc(Unicode, Integer, Unicode, Integer, _returns=Iterable(Integer)) def searchMethod(ctx, some, parameters): data = list(range(0)) print("the data:", data) yield from data
这样即使data是空列表,yield from data也会生成一个合法的空迭代器,不会触发异常,Spyne就能正确生成空SOAP数组响应。
验证效果
修改后,不管是直接返回空列表还是用生成器返回空迭代内容,Zeep客户端都会收到明确的空列表[],和生产服务器的行为完全一致。
如果你的生产环境WSDL要求数组元素必须存在(哪怕是空的),可以把Array的min_occurs参数设为1,进一步贴合生产环境的定义。
备注:内容来源于stack exchange,提问作者Herr R aus B

