2

我正在尝试使用 Spring WS + HttpClient 调用 Exchange WS 2010 API。我收到以下错误...

Jun/27 11:39:06,825 controller.AjaxCalendarController.[] - Unknown Error
org.springframework.ws.soap.client.SoapFaultClientException: The request is invalid.
    at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:37)
    at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:774)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:600)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:537)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:384)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)
    at org.jasig.portlet.calendar.adapter.ExchangeCalendarAdapter.retrieveExchangeEvents(ExchangeCalendarAdapter.java:171)
    at org.jasig.portlet.calendar.adapter.ExchangeCalendarAdapter.getEvents(ExchangeCalendarAdapter.java:132)
    at org.jasig.portlet.calendar.adapter.CalendarEventsDao.getEvents(CalendarEventsDao.java:74)
    at org.jasig.portlet.calendar.mvc.controller.AjaxCalendarController.getEventList(AjaxCalendarController.java:127)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
    at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:358)
    at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.doHandle(AnnotationMethodHandlerAdapter.java:345)
    at org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter.handleResource(AnnotationMethodHandlerAdapter.java:293)
    at org.springframework.web.portlet.DispatcherPortlet.doResourceService(DispatcherPortlet.java:825)
    at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:525)
    at org.springframework.web.portlet.FrameworkPortlet.serveResource(FrameworkPortlet.java:477)
    at org.jasig.portal.portlet.container.FilterChainImpl.doFilter(FilterChainImpl.java:212)
    at org.jasig.portal.portlet.container.FilterChainImpl.processFilter(FilterChainImpl.java:84)
    at org.jasig.portal.portlet.container.FilterManagerImpl.processFilter(FilterManagerImpl.java:103)
    at org.apache.pluto.container.driver.PortletServlet.dispatch(PortletServlet.java:350)
    at org.apache.pluto.container.driver.PortletServlet.doGet(PortletServlet.java:261)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:630)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
    at org.apache.pluto.driver.container.DefaultPortletInvokerService.invoke(DefaultPortletInvokerService.java:229)
    at org.apache.pluto.driver.container.DefaultPortletInvokerService.serveResource(DefaultPortletInvokerService.java:149)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
    at org.jasig.portal.portlet.dao.jpa.ThreadContextClassLoaderAspect.doThreadContextClassLoaderUpdate(ThreadContextClassLoaderAspect.java:63)
    at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy210.serveResource(Unknown Source)
    at org.apache.pluto.container.impl.PortletContainerImpl.doServeResource(PortletContainerImpl.java:203)
    at org.jasig.portal.portlet.rendering.PortletRendererImpl.doServeResource(PortletRendererImpl.java:598)
    at org.jasig.portal.portlet.rendering.worker.PortletResourceExecutionWorker.callInternal(PortletResourceExecutionWorker.java:54)
    at org.jasig.portal.portlet.rendering.worker.PortletResourceExecutionWorker.callInternal(PortletResourceExecutionWorker.java:32)
    at org.jasig.portal.portlet.rendering.worker.PortletExecutionWorker$1.call(PortletExecutionWorker.java:165)
    at org.jasig.portal.portlet.rendering.worker.PortletExecutionCallable.call(PortletExecutionCallable.java:119)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

它没有告诉我它认为请求有什么问题。:( 在服务器端,IIS 和 Exchange 都只是声明来自我的请求并返回了 HTTP 500。

这是 SOAP 信封(从日志中捕获):

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns2:GetUserAvailabilityRequest xmlns:ns2="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:ns3="http://schemas.microsoft.com/exchange/services/2006/types">
            <ns3:TimeZone>
                <ns3:Bias>0</ns3:Bias>
                <ns3:StandardTime>
                    <ns3:Bias>0</ns3:Bias>
                    <ns3:Time>02:00:00</ns3:Time>
                    <ns3:DayOrder>1</ns3:DayOrder>
                    <ns3:Month>11</ns3:Month>
                    <ns3:DayOfWeek>Sunday</ns3:DayOfWeek>
                </ns3:StandardTime>
                <ns3:DaylightTime>
                    <ns3:Bias>0</ns3:Bias>
                    <ns3:Time>02:00:00</ns3:Time>
                    <ns3:DayOrder>1</ns3:DayOrder>
                    <ns3:Month>3</ns3:Month>
                    <ns3:DayOfWeek>Sunday</ns3:DayOfWeek>
                </ns3:DaylightTime>
            </ns3:TimeZone>
            <ns2:MailboxDataArray>
                <ns3:MailboxData>
                    <ns3:Email>
                        <ns3:Name>Drew Wills</ns3:Name>
                        <ns3:Address>unicon@stcloudstate.edu</ns3:Address>
                    </ns3:Email>
                    <ns3:AttendeeType>Required</ns3:AttendeeType>
                    <ns3:ExcludeConflicts>false</ns3:ExcludeConflicts>
                </ns3:MailboxData>
            </ns2:MailboxDataArray>
            <ns3:FreeBusyViewOptions>
                <ns3:TimeWindow>
                    <ns3:StartTime>2012-06-27T00:00:00.000</ns3:StartTime>
                    <ns3:EndTime>2012-07-04T00:00:00.000</ns3:EndTime>
                </ns3:TimeWindow>
                <ns3:MergedFreeBusyIntervalInMinutes>60</ns3:MergedFreeBusyIntervalInMinutes>
                <ns3:RequestedView>DetailedMerged</ns3:RequestedView>
            </ns3:FreeBusyViewOptions>
        </ns2:GetUserAvailabilityRequest>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

这里还有一些显示 HTTP 标头等的跟踪日志记录......

Jun/27 11:39:06,773 conn.DefaultClientConnection.[] - Sending request: POST /EWS/exchange.asmx HTTP/1.1
Jun/27 11:39:06,773 http.wire.[] - >> "POST /EWS/exchange.asmx HTTP/1.1[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "Accept-Encoding: gzip[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "SOAPAction: "http://schemas.microsoft.com/exchange/services/2006/messages/GetUserAvailability"[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "Content-Type: text/xml; charset=utf-8[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "Content-Length: 1362[\r][\n]"
Jun/27 11:39:06,773 http.wire.[] - >> "Host: mail.stcloudstate.edu[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "Connection: Keep-Alive[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "Cookie: exchangecookie=49398e25ac5b4b84a19f93d170b3eefa[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "Cookie2: $Version=1[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "Authorization: NTLM xxx[\r][\n]"
Jun/27 11:39:06,774 http.wire.[] - >> "[\r][\n]"
Jun/27 11:39:06,774 http.headers.[] - >> POST /EWS/exchange.asmx HTTP/1.1
Jun/27 11:39:06,774 http.headers.[] - >> Accept-Encoding: gzip
Jun/27 11:39:06,774 http.headers.[] - >> Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Jun/27 11:39:06,774 http.headers.[] - >> SOAPAction: "http://schemas.microsoft.com/exchange/services/2006/messages/GetUserAvailability"
Jun/27 11:39:06,774 http.headers.[] - >> Content-Type: text/xml; charset=utf-8
Jun/27 11:39:06,774 http.headers.[] - >> Content-Length: 1362
Jun/27 11:39:06,774 http.headers.[] - >> Host: mail.stcloudstate.edu
Jun/27 11:39:06,774 http.headers.[] - >> Connection: Keep-Alive
Jun/27 11:39:06,774 http.headers.[] - >> User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Jun/27 11:39:06,774 http.headers.[] - >> Cookie: exchangecookie=49398e25ac5b4b84a19f93d170b3eefa
Jun/27 11:39:06,775 http.headers.[] - >> Cookie2: $Version=1
Jun/27 11:39:06,775 http.headers.[] - >> Authorization: NTLM xxx
Jun/27 11:39:06,776 http.wire.[] - >> "<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><ns2:GetUserAvailabilityRequest xmlns:ns2="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:ns3="http://schemas.microsoft.com/exchange/services/2006/types"><ns3:TimeZone><ns3:Bias>0</ns3:Bias><ns3:StandardTime><ns3:Bias>0</ns3:Bias><ns3:Time>02:00:00</ns3:Time><ns3:DayOrder>1</ns3:DayOrder><ns3:Month>11</ns3:Month><ns3:DayOfWeek>Sunday</ns3:DayOfWeek></ns3:StandardTime><ns3:DaylightTime><ns3:Bias>0</ns3:Bias><ns3:Time>02:00:00</ns3:Time><ns3:DayOrder>1</ns3:DayOrder><ns3:Month>3</ns3:Month><ns3:DayOfWeek>Sunday</ns3:DayOfWeek></ns3:DaylightTime></ns3:TimeZone><ns2:MailboxDataArray><ns3:MailboxData><ns3:Email><ns3:Name>Drew Wills</ns3:Name><ns3:Address>unicon@stcloudstate.edu</ns3:Address></ns3:Email><ns3:AttendeeType>Required</ns3:AttendeeType><ns3:ExcludeConflicts>false</ns3:ExcludeConflicts></ns3:MailboxData></ns2:MailboxDataArray><ns3:FreeBusyViewOptions><ns3:TimeWindow><ns3:StartTime>2012-06-27T00:00:00.000</ns3:StartTime><ns3:EndTime>2012-07-04T00:00:00.000</ns3:EndTime></ns3:TimeWindow><ns3:MergedFreeBusyIntervalInMinutes>60</ns3:MergedFreeBusyIntervalInMinutes><ns3:RequestedView>DetailedMerged</ns3:RequestedView></ns3:FreeBusyViewOptions></ns2:GetUserAvailabilityRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>"
Jun/27 11:39:06,801 http.wire.[] - << "HTTP/1.1 500 Internal Server Error[\r][\n]"
Jun/27 11:39:06,801 http.wire.[] - << "Cache-Control: private[\r][\n]"
Jun/27 11:39:06,801 http.wire.[] - << "Transfer-Encoding: chunked[\r][\n]"
Jun/27 11:39:06,801 http.wire.[] - << "Content-Type: text/xml; charset=utf-8[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "Server: Microsoft-IIS/7.5[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "X-AspNet-Version: 2.0.50727[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "Persistent-Auth: true[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "X-Powered-By: ASP.NET[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "Date: Wed, 27 Jun 2012 18:39:05 GMT[\r][\n]"
Jun/27 11:39:06,802 http.wire.[] - << "[\r][\n]"
Jun/27 11:39:06,802 conn.DefaultClientConnection.[] - Receiving response: HTTP/1.1 500 Internal Server Error
Jun/27 11:39:06,802 http.headers.[] - << HTTP/1.1 500 Internal Server Error
Jun/27 11:39:06,802 http.headers.[] - << Cache-Control: private
Jun/27 11:39:06,802 http.headers.[] - << Transfer-Encoding: chunked
Jun/27 11:39:06,802 http.headers.[] - << Content-Type: text/xml; charset=utf-8
Jun/27 11:39:06,802 http.headers.[] - << Server: Microsoft-IIS/7.5
Jun/27 11:39:06,802 http.headers.[] - << X-AspNet-Version: 2.0.50727
Jun/27 11:39:06,802 http.headers.[] - << Persistent-Auth: true
Jun/27 11:39:06,802 http.headers.[] - << X-Powered-By: ASP.NET
Jun/27 11:39:06,802 http.headers.[] - << Date: Wed, 27 Jun 2012 18:39:05 GMT
Jun/27 11:39:06,804 exchange.NtlmAuthHttpClient.[] - Connection can be kept alive indefinitely
Jun/27 11:39:06,808 http.wire.[] - << "247[\r][\n]"
Jun/27 11:39:06,808 http.wire.[] - << "<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode xmlns:a="http://schemas.microsoft.com/exchange/services/2006/types">a:ErrorInvalidRequest</faultcode><faultstring xml:lang="en-US">The request is invalid.</faultstring><detail><e:ResponseCode xmlns:e="http://schemas.microsoft.com/exchange/services/2006/errors">ErrorInvalidRequest</e:ResponseCode><e:Message xmlns:e="http://schemas.microsoft.com/exchange/services/2006/errors">The request is invalid.</e:Message></detail></s:Fault></s:Body></s:Envelope>"
Jun/27 11:39:06,808 http.wire.[] - << "[\r][\n]"
Jun/27 11:39:06,808 http.wire.[] - << "0[\r][\n]"
Jun/27 11:39:06,808 http.wire.[] - << "[\r][\n]"
Jun/27 11:39:06,809 tsccm.ThreadSafeClientConnManager.[] - Released connection is reusable.

非常感谢您对这个棘手问题的任何帮助。

4

3 回答 3

2

我遇到了同样的问题——本地 Exchange 2010 安装的 EWS 服务拒绝包含空的“soap-env:header”元素的请求。我使用带有以下 SOAP XML 的 cURL 验证了该问题:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
    <ns2:GetFolder xmlns:ns2="http://schemas.microsoft.com/exchange/services/2006/messages"
                   xmlns:ns3="http://schemas.microsoft.com/exchange/services/2006/types">
        <ns2:FolderShape>
            <ns3:BaseShape>Default</ns3:BaseShape>
        </ns2:FolderShape>
        <ns2:FolderIds>
            <ns3:DistinguishedFolderId Id="inbox"/>
        </ns2:FolderIds>
    </ns2:GetFolder>
</SOAP-ENV:Body>

奇怪的是,我可以通过对请求中的“SOAP-ENV:Header”元素进行以下任何更改来让 EWS 服务接受请求:

  1. 如上所述将 RequestServerVersion 添加到标头
  2. 完全删除“SOAP-ENV:Header”元素
  3. 将单标签空元素替换为“双标签”空元素:

在我看来,这就像 Exchange 2010 EWS 中的一个错误。

于 2012-09-24T20:12:12.680 回答
2

因此,如果您将客户端从图片中取出,并简单地使用 curl 模拟请求,您能否验证您仍然得到 500 响应?

这至少会将问题隔离到服务器端。

通过使用 HTTP 标头值或 soap 实体的内容,您可以更轻松地使用 curl 调试问题。

于 2012-06-27T19:37:13.647 回答
1

我得到它的工作 - 这是细节......

我使用 SoapUI 获得了一些见解。我想测试我的 SOAP 信封(由我的代码生成)但是...“soapUI 当前不支持 NTLMv2,因此如果您的服务器需要这个,您将需要重新配置服务器以接受NTLMv1(见...)或使用(...)之类的产品来克服这个问题。”

我并不感到惊讶。NTLM AuthN 是前两天的噩梦,在 Java 中工作是一个怪物。 这篇文章很有帮助,但在我的情况下,我还不得不强制我的代码为“协商”(SPNEGO)方案发送 NTLM 凭据。(它会选择 kerberos,但放弃了,因为它没有 kerberos 凭据......啊!)

SoapUI 还可以生成一个示例请求,我对此进行了审查。它看起来很像我的,但还有一些可选的(看似)位。大多数是可选的,但显然不是。

Web 服务需要这个肥皂头:

<SOAP-ENV:Header><ns3:RequestServerVersion xmlns:ns3="http://schemas.microsoft.com/exchange/services/2006/types" Version="Exchange2010_SP2"/></SOAP-ENV:Header>

MSDN API 文档soap header 是可选的,但是当我发送它时它就开始工作了。

于 2012-06-28T13:01:24.743 回答