【问题标题】:Groovy HttpBuilder - Get Body Of Failed ResponseGroovy HttpBuilder - 获取失败响应的主体
【发布时间】:2013-11-26 19:23:23
【问题描述】:

我正在尝试使用 Groovy HTTPBuilder 编写一个集成测试,以验证正文中是否返回了正确的错误消息以及 HTTP 409 状态消息。但是,我无法弄清楚在失败情况下如何实际访问 HTTP 响应的正文。

http.request(ENV_URL, Method.POST, ContentType.TEXT) {
    uri.path = "/curate/${id}/submit"
    contentType = ContentType.JSON
    response.failure = { failresp_inner ->
        failresp = failresp_inner
    }
}

then:
assert failresp.status == 409
// I would like something like 
//assert failresp.data == "expected error message"

这是来自服务器的 HTTP 响应的样子:

2013-11-13 18:17:58,726 DEBUG  wire - << "HTTP/1.1 409 Conflict[\r][\n]"
2013-11-13 18:17:58,726 DEBUG  wire - << "Date: Wed, 13 Nov 2013 23:17:58 GMT[\r][\n]"
2013-11-13 18:17:58,726 DEBUG  wire - << "Content-Type: text/plain[\r][\n]"
2013-11-13 18:17:58,726 DEBUG  wire - << "Transfer-Encoding: chunked[\r][\n]"
2013-11-13 18:17:58,727 DEBUG  wire - << "[\r][\n]"
2013-11-13 18:17:58,728 DEBUG  wire - << "E[\r][\n]"
2013-11-13 18:17:58,728 DEBUG  wire - << "expected error message"
2013-11-13 18:17:58,728 DEBUG  wire - << "[\r][\n]"
2013-11-13 18:17:58,728 DEBUG  wire - << "0[\r][\n]"
2013-11-13 18:17:58,728 DEBUG  wire - << "[\r][\n]"

【问题讨论】:

    标签: groovy httpbuilder


    【解决方案1】:

    我最近在尝试使用 Spock 集成测试我的 REST 端点时遇到了这个问题。我以 Sam 的回答为灵感并最终对其进行了改进,以便继续利用 HttpBuilder 提供的自动转换。搞砸了一段时间后,我有了一个好主意,就是将成功处理程序闭包分配给失败处理程序,以标准化行为,而不管返回什么状态码。

    client.handler.failure = client.handler.success
    

    一个例子:

    ...
    
    import static org.apache.http.HttpStatus.*
    
    ...
    
    private RESTClient createClient(String username = null, String password = null) {
        def client = new RESTClient(BASE_URL)
        client.handler.failure = client.handler.success
    
        if(username != null)
            client.auth.basic(username, password)
    
        return client
    }
    
    ...
    
    def unauthenticatedClient = createClient()
    def userClient = createClient(USER_USERNAME, USER_PASSWORD)
    def adminClient = createClient(ADMIN_USERNAME, ADMIN_PASSWORD)
    
    ...
    
    def 'get account'() {
        expect:
        // unauthenticated tries to get user's account
        unauthenticatedClient.get([path: "account/$USER_EMAIL"]).status == SC_UNAUTHENTICATED
    
        // user gets user's account
        with(userClient.get([path: "account/$USER_EMAIL"])) {
            status == SC_OK
            with(responseData) {
                email == USER_EMAIL
                ...
            }
        }
    
        // user tries to get user2's account
        with(userClient.get([path: "account/$USER2_EMAIL"])) {
            status == SC_FORBIDDEN
            with(responseData) {
                message.contains(USER_EMAIL)
                message.contains(USER2_EMAIL)
                ...
            }
        }
    
        // admin to get user's account
        with(adminClient.get([path: "account/$USER_EMAIL"])) {
            status == SC_OK
            with(responseData) {
                email == USER_EMAIL
                ...
            }
        }
    }
    

    【讨论】:

    • 美丽的简洁!谢谢!
    • @Jon 我不久前问了一个类似的问题,这将受益于类似的答案。如果/当我有机会时,我会写下来,但你应该随时击败我。 stackoverflow.com/questions/19546762/…
    【解决方案2】:

    如果你使用它是否有效:

    response.failure = { resp, reader ->
        failstatus = resp.statusLine
        failresp   = reader.text
    }
    

    【讨论】:

    • 感谢您的建议,我实际上已经尝试过了,它导致闭包不再具有正确的参数,因此整个方法只是抛出。
    【解决方案3】:

    当我开始使用 HttpBuilder 时,我也遇到了这个问题。我想出的解决方案是定义 HTTPBuilder 成功和失败闭包以返回一致的值,如下所示:

    HTTPBuilder http = new HTTPBuilder()
    http.handler.failure = { resp, reader ->
        [response:resp, reader:reader]
    }
    http.handler.success = { resp, reader ->
        [response:resp, reader:reader]
    }
    

    如此定义,您的 HTTPBuilder 实例将始终返回包含 response 对象(HttpResponseDecorator 的实例)和 reader 对象的映射。您的请求将如下所示:

    def map = http.request(ENV_URL, Method.POST, ContentType.TEXT) {
        uri.path = "/curate/${id}/submit"
        contentType = ContentType.JSON
    }
    
    def response = map['response']
    def reader = map['reader']
    
    assert response.status == 409
    

    读者将是某种对象,它可以让您访问响应主体,您可以通过调用 getClass() 方法来确定响应主体的类型:

    println "reader type: ${reader.getClass()}"
    

    阅读器对象的类型将由响应中的 Content-Type 标头确定。您可以通过在请求中添加“Accept”标头来具体告诉服务器您希望返回什么。

    【讨论】:

      猜你喜欢
      • 2012-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多