十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Feign SOAP 编解码实战:用 feign-soap-jakarta 模块实现 SOAP 1.1/1.2 客户端与 SOAPFault 处理

Feign SOAP 编解码实战:用 feign-soap-jakarta 模块实现 SOAP 1.1/1.2 客户端与 SOAPFault 处理 后端API设计【免费下载链接】feignFeign makes writing java http clients easier项目地址https://gitcode.com/gh_mirrors/fe/feign点击查看免费下载本指南以 OpenFeign 仓库中的soap-jakarta模块为核心讲解如何借助 JAXB 与 SOAPMessage 在 Feign 中完成 SOAP Body 的编码请求序列化与解码响应反序列化并系统说明 SOAPFault 的两种捕获路径200 状态码内嵌 Fault 与 4xx/5xx 错误码。读完本文你将掌握SOAPCodec、SOAPEncoder、SOAPDecoder、SOAPErrorDecoder四个类的配置方式、Builder 参数语义以及应对命名空间丢失场景的useFirstChild技巧。一、模块定位Feign 的 SOAP 能力从何而来soap-jakarta是 Feign 生态中面向 Jakarta EEjakarta.xml.*命名空间的 SOAP 编解码模块对应模块坐标feign-soap-jakarta其定位在 soap-jakarta/README.md 中表述得非常清晰通过 JAXB 与 SOAPMessage 完成 SOAP Body 对象的编码与解码提供 SOAPFault 解码能力把 Fault 包装回标准的jakarta.xml.ws.soap.SOAPFaultException这样调用方只需要捕获SOAPFaultException即可统一处理 SOAP Fault。模块代码位于 soap-jakarta/src/main/java/feign/soap/由 4 个类构成类职责SOAPCodec组合 Encoder Decoder 的便捷门面实现feign.codec.CodecSOAPEncoder将 JAXB 注解对象 marshal 进 SOAPMessage 并写入请求体SOAPDecoder从 SOAPMessage 响应体中 unmarshal 出 JAXB 对象或抛出SOAPFaultExceptionSOAPErrorDecoder针对非 2xx 响应把 Fault 包装为SOAPFaultException否则回退默认 ErrorDecoder从 soap-jakarta/pom.xml 可以看到其依赖feign-core、feign-jaxb-jakarta提供JAXBContextFactory、jakarta.xml.ws-api、jakarta.xml.soap-api、jakarta.xml.bind-api并引入saaj-impl与jaxb-implruntime作为实现。该模块基于 Jakarta 命名空间与基于javax.xml.*的soap模块见 soap/README.md内容基本对称适合迁移到 Jakarta EE 环境的项目。说明SOAPCodec、SOAPEncoder、SOAPDecoder在源码中标注了Experimental见 SOAPCodec.javaAPI 细节在后续版本中仍可能演进生产使用前请留意版本变更。二、最小可运行示例用 SOAPCodec 一步到位文档给出的第一种接入方式是把SOAPCodec整体注册到Feign.Builder。它内部由SOAPEncoder与SOAPDecoder组成见 SOAPCodec.javaencoder()/decoder()分别返回二者public interface MyApi { RequestLine(POST /getObject) Headers({ SOAPAction: getObject, Content-Type: text/xml }) MyJaxbObjectResponse getObject(MyJaxbObjectRequest request); } ... JAXBContextFactory jaxbFactory new JAXBContextFactory.Builder() .withMarshallerJAXBEncoding(UTF-8) .withMarshallerSchemaLocation(http://apihost http://apihost/schema.xsd) .build(); api Feign.builder() .codec(new SOAPCodec(jaxbFactory)) .target(MyApi.class, http://api); ... try { api.getObject(new MyJaxbObjectRequest()); } catch (SOAPFaultException faultException) { log.info(faultException.getFault().getFaultString()); }这个示例有几个要点Headers中必须显式声明Content-Type: text/xml因为SOAPEncoder.canEncode与SOAPDecoder.canDecode均通过Util.isXmlContentType(...)判断是否为 XML 内容类型见 SOAPEncoder.java 与 SOAPDecoder.java且这两个类实现了PredicatedEncoder/PredicatedDecoder只有在命中 XML Content-Type 时才参与编解码SOAPAction头用于 SOAP 1.1 的 Action 路由约定按目标服务要求填写SOAPFaultException的getFault()返回SOAPFault可继续取getFaultString()、getFaultCode()等细节。三、编码器与解码器分开配置SOAPEncoder / SOAPDecoder如果只需要单向能力或者希望分别定制编码与解码参数文档提供了第二种方式api Feign.builder() .encoder(new SOAPEncoder(jaxbFactory)) .decoder(new SOAPDecoder(jaxbFactory)) .target(MyApi.class, http://api);3.1 编码链路SOAPEncoder从 SOAPEncoder.java 的实现看编码过程分四步用DocumentBuilderFactory创建空Document通过JAXBContextFactory.createMarshaller(bodyType)取得 Marshaller把请求对象 marshal 进 Document用MessageFactory.newInstance(soapProtocol)创建SOAPMessage将 Document 添加到 SOAP Body调用modifySOAPMessage钩子后把整封 SOAP 消息写入请求体默认走soapMessage.writeTo(bos)。其中JAXBContextFactory由feign-jaxb-jakarta模块提供内部用ConcurrentHashMap缓存 JAXBContext避免重复创建这一昂贵操作见 JAXBContextFactory.java。因此文档明确建议JAXBContextFactory应在多次请求间复用。SOAPEncoder只支持原始类型raw type作为 Body 类型encode方法会先检查bodyType instanceof Class否则抛出UnsupportedOperationExceptionSOAPEncoder.java。这一约束同样体现在测试doesntEncodeParameterizedTypes中SOAPCodecTest.java编码参数化类型MapString, ?会直接失败。3.2 解码链路SOAPDecoderSOAPDecoder.java 的解码流程为状态码 404 且启用了Feign.Builder#dismiss404()时返回Util.emptyValueOf(type)测试notFoundDecodesToNull验证了这一点SOAPCodecTest.java响应体为空时返回 null用MessageFactory从响应输入流创建SOAPMessage若 SOAP Body 存在且hasFault()为真直接抛出SOAPFaultException——这正是文档所说“Fault 可能以 200 状态码返回HTTP 层无错误”时的兜底处理否则用JAXBContextFactory.createUnmarshaller(type)反序列化 Body 内容。SOAPDecoder同样只接受原始类型参数化类型会抛DecodeException见doesntDecodeParameterizedTypes测试SOAPCodecTest.java。四、捕获 SOAPFault 的第二种姿势SOAPErrorDecoder不同服务端对 Fault 的返回策略不一致有的把 Fault 放在 200 响应里HTTP 层“成功”有的则返回 4xx/5xx。前者由SOAPDecoder的hasFault()分支处理后者则需要SOAPErrorDecoder。文档给出的配置如下api Feign.builder() .codec(new SOAPCodec(jaxbFactory)) .errorDecoder(new SOAPErrorDecoder()) .target(MyApi.class, http://api);SOAPErrorDecoder.java 的逻辑是响应体为空或状态码为 503 时直接回退到DefaultErrorDecoder测试errorDecoderReturnsFeignExceptionOn503Status验证了 503 返回FeignException见 SOAPFaultDecoderTest.java否则解析 SOAP 消息若 Body 中有 Fault则包装为SOAPFaultException返回若解析失败或没有 Fault同样回退DefaultErrorDecoder保持默认的异常与重试语义测试errorDecoderReturnsFeignExceptionOnEmptyFault验证了空 Fault 时返回FeignExceptionSOAPFaultDecoderTest.java。这样设计的好处是无论 Fault 以何种 HTTP 状态码出现调用方都只需捕获SOAPFaultException非 Fault 错误仍然走 Feign 标准的FeignException流程不破坏既有重试与异常传播行为。SOAPErrorDecoder还提供一个带soapProtocol参数的构造器用于指定 SOAP 协议版本默认使用SOAPConstants.DEFAULT_SOAP_PROTOCOLSOAPErrorDecoder.java。五、命名空间丢失的救星SOAPDecoder 的 useFirstChild 选项文档专门指出一类实际问题SOAP Envelope 上的命名空间声明在某些情况下不会被 JAXB 在读取文档时继承而当 XML 源头无法修正时尤其棘手。解决方法是SOAPDecoder.Builder上的useFirstChild()SOAPDecoder decoder new SOAPDecoder.Builder() .withJAXBContextFactory(jaxbFactory) .useFirstChild() .build();其原理在 SOAPDecoder.java开启后改用SOAPBody#getFirstChild()定位 Body 内容节点替代默认的SOAPBody#extractContentAsDocument()。配套做法是提供package-info.java显式管理元素命名空间与缺失声明时的行为。仓库测试中已有现成范本soap-jakarta/src/test/java/feign/soap/package-info.java 使用了XmlSchema(elementFormDefault XmlNsForm.UNQUALIFIED)。测试decodesSoapWithSchemaOnEnvelope展示了典型场景Envelope 上声明了xsi、xsd等命名空间与xsi:noNamespaceSchemaLocationBody 内元素引用xsi:typexsd:string此时开启useFirstChild()才能正确反序列化SOAPCodecTest.java。六、Builder 参数速查可定制项与默认值两个编解码器都提供了完善的 Builder可配置项汇总如下依据 SOAPEncoder.java 与 SOAPDecoder.javaBuilder 方法所属默认值说明withJAXBContextFactory(...)Encoder / Decoder必填否则build()抛IllegalStateException提供 Marshaller/Unmarshaller 的 JAXBContextFactorywithWriteXmlDeclaration(boolean)Encodertrue是否在输出中写入 XML 声明withCharsetEncoding(Charset)EncoderUTF-8请求体字符编码同时写入CHARACTER_SET_ENCODING属性withSOAPProtocol(String)Encoder / DecoderSOAP_1_1_PROTOCOLEncoder/DEFAULT_SOAP_PROTOCOLDecoder可选SOAP_1_1_PROTOCOL、SOAP_1_2_PROTOCOL、DYNAMIC_SOAP_PROTOCOLwithFormattedOutput(boolean)Encoderfalse为 true 时用 Transformer 以 4 空格缩进美化输出useFirstChild()Decoderfalse用getFirstChild()替代extractContentAsDocument()解析 Body这些参数都有对应测试佐证encodesSoapWithCustomJAXBMarshallerEncoding验证 UTF-16 编码下请求体按 UTF-16LE 生成SOAPCodecTest.javaencodesSoapWithCustomJAXBFormattedOuput验证缩进输出格式SOAPCodecTest.javadecodesSoap1_2Protocol验证 SOAP 1.2 解码SOAPCodecTest.java。此外JAXBContextFactory.Builder本身也支持withMarshallerJAXBEncoding、withMarshallerSchemaLocation、withMarshallerNoNamespaceSchemaLocation、withMarshallerFormattedOutput等选项它们最终以属性形式写入 Marshaller/UnmarshallerJAXBContextFactory.java并在编码/解码时生效对应测试覆盖了 schemaLocation 与 noNamespaceSchemaLocation 的输出效果。七、进阶定制modifySOAPMessage 钩子与 SOAP HeaderSOAPEncoder原生不支持直接添加 SOAP Header但提供了 protected 方法modifySOAPMessage(SOAPMessage)作为扩展点SOAPEncoder.java。文档的类注释中给出了添加 WS-Security 用户令牌头的示例通过SOAPFactory创建Security/UsernameToken元素并挂到soapMessage.getSOAPHeader()上。仓库测试changeSoapProtocolAndSetHeader是这一钩子的完整落地ChangedProtocolAndHeaderSOAPEncoder继承SOAPEncoder在构造时把协议切换为SOAP_1_2_PROTOCOL并覆写modifySOAPMessage添加wss:Security头最终断言生成的 Envelope 同时包含env:前缀与安全头SOAPCodecTest.java。当需要携带 WS-Security、事务令牌等自定义 Header 时优先考虑继承SOAPEncoder覆写此钩子而不是手工拼接 XML。八、关键约束与边界行为小结综合文档与源码接入soap-jakarta时需要牢记以下边界仅支持原始类型编码/解码的 Body 类型必须是具体类Class参数化泛型会被拒绝UnsupportedOperationException/DecodeException。但带XmlElement泛型字段的类如测试中的BoxT仍可正常使用见decodeAnnotatedParameterizedTypesSOAPCodecTest.java。Content-Type 必须为 XMLcanEncode/canDecode依赖Util.isXmlContentType请保持text/xml之类的声明。SOAPFault 双通道200 响应内嵌 Fault 由SOAPDecoder抛出SOAPFaultException4xx/5xx 响应由SOAPErrorDecoder包装为SOAPFaultException其余错误回退默认解码器。503 例外SOAPErrorDecoder对 503 直接走默认解码不解析 Fault。JAXBContextFactory 复用其内部缓存 JAXBContextConcurrentHashMap跨请求复用可显著降低开销。命名空间问题遇到 Envelope 声明不被继承的情况启用useFirstChild()并结合package-info.java显式声明命名空间。按上述约束接入后即可在 Feign 声明式接口下获得完整的 SOAP 1.1/1.2 客户端能力请求自动包装进 SOAP Envelope、响应自动解包为 JAXB 对象、Fault 统一收敛为SOAPFaultException从而让 SOAP 服务调用与 REST 调用一样简洁。赞分享后端API设计【免费下载链接】feignFeign makes writing java http clients easier项目地址https://gitcode.com/gh_mirrors/fe/feign点击查看免费下载相关推荐Feign SOAP Codec 实战用 JAXB 与 SOAPMessage 构建声明式 SOAP Web 服务客户端Feign SOAP Codec 实战用 JAXB 与 SOAPMessage 构建声明式 SOAP Web 服务客户端 导读 Feign 的 soap 模块后端API设计Ideogram-4-nf4 与 diffusers 集成高级 API 使用完全指南Ideogram 4 nf4 与 diffusers 集成高级 API 使用完全指南 想要掌握业界领先的 Ideogram 4 nf4 图像生成模型与 dif推荐Go Soap — 简洁高效的SOAP客户端库推荐Go Soap — 简洁高效的SOAP客户端库 在现代化的软件开发中集成不同系统的服务是必不可少的一环而这往往涉及到对老旧但依然广泛使用的SOAP协议上一篇开源项目Triton 推理服务器 Python 后端教程下一篇remark语法高亮功能深度解析支持40编程语言的完美呈现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表