从SOAP响应获取HTTP状态码

13

如何从SOAPConnection.call()的结果中获取HTTP状态?


javax.xml.soap.SOAPConnection类有一个名为"call()"的方法,它返回一个SOAPMessage。SOAPMessage可以有各种响应。例如,一个带有HTTP 200、HTTP 500等消息。我需要从该SOAPMessage中找出HTTP代码。 - asthiwanka
我认为,如果http状态200 OK不同,您将收到SOAPException - Andremoniy
5个回答

11

摘自W3C有关SOAP的笔记(第6.2节)

SOAP HTTP 遵循 HTTP 状态代码的语义,用于在 HTTP 中传递状态信息。例如,2xx 状态码表明客户端请求包括 SOAP 组件已成功接收、理解和接受等。

如果处理请求时出现 SOAP 错误,则 SOAP HTTP 服务器必须发出 HTTP 500“内部服务器错误”响应,并在响应中包含一个包含 SOAP 故障元素(参见第4.4节)指示 SOAP 处理错误的 SOAP 消息。

并且从API中的SOAPFault文档中得知:

SOAPBody 对象中的一个元素,包含错误和/或状态信息。这些信息可能涉及到 SOAPMessage 对象中的错误,或者与消息内容本身无关的问题。

因此,可能的答案为

SoapMessage soapMessage = null;
soapMessage = MySOAPConnection.call(...);
soapMessage.getSOAPPart().getEnvelope().getBody().getFault().getFaultCode();

对我回答有所帮助的参考资料包括:


1
是的。但是,soapMessage.getSOAPPart().getEnvelope().getBody().getFault().getFaultCode() 的作用是提供 SOAP 响应中的故障代码。尽管 HTTP 标头不在 SOAP 响应本身中。因此,使用此方法无法提取 HTTP 状态码,对吧? - asthiwanka

6
简单的回答是你做不到。在分析HttpSOAPConnection代码时,使用一个局部的HttpURLConnection对象实例来与目标服务进行实际通信。这确实获取了httpResponse代码,但是完全隐藏了它。你可以得出的结论是:如果没有抛出异常,但返回的SOAPMessage包含一个SOAPFault,那么返回代码就是HttpURLConnection.HTTP_INTERNAL_ERROR (即500)。没有异常和SOAPFault意味着返回代码是200到206之间的,都是“成功” - 不幸的是,HttpURLConnection对象中的HTTP头文件中的状态条目明确未复制到返回的SOAPMessage的MIMEHeaders中……
// Header field 0 is the status line so we skip it.

任何其他内容都将引发异常,代码将从异常消息字段中的开括号后开始,并且可能是三位数字,很难确定,因为有人忘记在消息之前添加闭括号或其他分隔符...

throw new SOAPExceptionImpl(
                    "Bad response: ("
                        + responseCode
                        + httpConnection.getResponseMessage());

例如:
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (502internal error - server connection terminated

在异常处理中依赖文本消息的格式非常糟糕,但是响应代码在其他任何地方都没有暴露出来。


截至2020年,Java 8仍然是这样的 :( 我实际上不得不重新实现SAAJ的SOAP-HTTP客户端(因为主机名验证器),而且非常容易修补一些"maybeRC"。将迭代器更改为从0开始,并添加header.add...用于key=null情况(我知道,这可能是错误的,这就是为什么使用"maybeRC")。 - DraxDomax

2
另一种选择(Java 8):
public class HttpResponseHandler implements SOAPHandler<SOAPMessageContext> {
    private Logger log = Logger.create(HttpResponseHandler.class);

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        boolean outboundProperty = (boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); // Response
        if(!outboundProperty) {
            int status = (int)context.get(MessageContext.HTTP_RESPONSE_CODE);
            log.debug("HTTP status code = " + status);
        }
        return true;
    }
}

// Usage : building your service

List<Handler> soapHandlers = new ArrayList();
soapHandlers.add(new HttpResponseHandler());

URL wsdlDocumentLocation = this.getClass().getResource("some_url");
Service service = Service.create(wsdlDocumentLocation, new QName("namespace", "servicename"));
service.setHandlerResolver(new HandlerResolver() {
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        return soapHandlers;
    }
});
BindingProvider provider = (BindingProvider)service.getPort(new QName("namespace", "portname"), serviceInterface);
provider.getRequestContext().put("javax.xml.ws.service.endpoint.address", this.endpointAddress);
provider.getRequestContext().put("com.sun.xml.ws.connect.timeout", connectTimeout);
provider.getRequestContext().put("com.sun.xml.ws.request.timeout", requestTimeout);
return provider;

1

0

我确实有与这个问题相同的要求,业务分析师希望记录与每个传入和传出的SOAP调用相关的每个HTTP响应代码。我的答案适用于Apache CXF 2.7.5。

您可以通过在javax.xml.ws.handler.soap.SoapHandler接口的实现中使用以下代码片段来访问HTTP状态码。

int status = (( javax.servlet.http.HttpServletResponse)messageContext.get("HTTP.RESPONSE")).getStatus();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接