Groovy HTTP Builder:空POST响应导致SAXParseException

时间:2013-12-03 11:27:43

标签: java groovy httpbuilder

我正在为YouTrack API实现REST客户端。每当我的POST请求返回空响应时,我都会收到异常(只有一个有效的标头)。 HTTP状态代码为200。 这就是堆栈跟踪:

[Fatal Error] :-1:-1: Premature end of file.
gru 03, 2013 10:34:49 AM groovyx.net.http.HTTPBuilder doRequest
WARNING: Error parsing 'application/xml; charset=UTF-8' response
org.xml.sax.SAXParseException; Premature end of file.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:181)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:234)
at groovyx.net.http.ParserRegistry.parseXML(ParserRegistry.java:267)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1085)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:952)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at groovyx.net.http.HTTPBuilder.parseResponse(HTTPBuilder.java:561)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:494)
at groovyx.net.http.RESTClient.post(RESTClient.java:140)
at groovyx.net.http.RESTClient$post.callCurrent(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at groovy.YouTrackRest.releaseVersion(YouTrackRest.groovy:66)
at groovy.YouTrackRest$releaseVersion$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at YouTrack.run(YouTrack.groovy:13)
[...]

我已经调试并发现了直接原因。我注意到在groovyx.net.http.HTTPBuilder:492中,在解析之前检查响应是否为空,但在我的情况下,调用entity.getContentLength()返回-1。在Apache documentation for HttpEntity之后 内容的字节数,如果未知则为负数

我的客户端实现非常简单。我通过捕获HttpResponseException并断言statusCode 200解决了这个问题。我仍在控制台中获取堆栈跟踪,但这可能只是记录器设置。

我的实施:

import groovyx.net.http.RESTClient

class YouTrackRest extends RESTClient { 
[...]
def activateVersion(versionNumber) {
    try {
        post(
                path: getVersionPath(versionNumber),
                body: [
                        colorIndex: ACTIVE_COLOR_INDEX,
                        released: false,
                        releaseDate: null,
                        archived: false,
                        newName: versionNumber

                ]
        )
    } catch (HttpResponseException ex) {
        assert ex.response.status == 200
    }
}

修改 这些是响应标头

Server: nginx
Date: Fri, 06 Dec 2013 10:36:10 GMT
Content-Type: application/xml; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: JSESSIONID=ny2s3cxwsvveya6vgwj2fmig;Path=/youtrack
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache, no-store, no-transform, must-revalidate

现在Transfer-Encoding: chunked标题解释了缺少'Content-Length'标题。这必须是未知内容长度的原因。 现在,根据Wikipedia ,数据传输由长度为零的最终块终止。那么也许这种情况下第一个块也是最后一个?

Web服务器和Http客户端库都是我的第三方。我想提出一个行为不端的问题:

  • YouTrack REST WS promisses XML并且不返回任何内容
  • groovyx.net.http.HTTPBuilder无法处理分块编码的响应。

我将非常乐于帮助我了解这个问题。

2 个答案:

答案 0 :(得分:1)

我只是使用遇到了同样的问题。我可以通过以下方法解决它:

def service = new HTTPBuilder(...)
service.request(Method.POST, ContentType.JSON) {
    uri.path = ...
    body = ...

    response.'200' = { resp ->
            logInfo resp.statusLine
    }

    response.success = { resp, result ->
            logInfo resp.statusLine
    }

    response.failure = { resp ->
            logError resp.statusLine
    }
}

如果响应为200,则基本上不要尝试解析正文。

答案 1 :(得分:0)

显然问题是由非标准WS响应引起的:HTTP状态200和空响应主体。要么是HTTP状态204,要么是有效的XML主体和状态200.

我在WS提供商处报告了issue。希望它会得到解决。我将问题标记为已回答

感谢@tim_yates和@Ian Roberts的有用评论。