当前位置: 首页 > 工具软件 > groovy-http > 使用案例 >

groovy http_Groovy和HTTP

阳宾实
2023-12-01

groovy http

本文最初发表在GroovyMag的 2012年12月号上。

Groovy使与Web交互更容易的一些不同方式

Groovy的主要优点之一是它简化了我们在Java中处理的一些常见方案。 带有条件,错误处理和许多其他问题的复杂代码可以非常简洁易懂的方式表示。 本文将介绍一些与通过HTTP与内容进行交互有关的便捷Groovy主义。 首先,我们将研究添加到标准Java类中的一些语法糖,这些语法可以简化GET和POST请求,然后我们将研究如何

HTTPBuilder模块提供了用于使用HttpClient库的DSL。

测试项目

为了提供一个建立网站和演示各种HTTP请求的环境,我们将使用Gradle Jetty插件和一些简单的Groovlets 。 完整的源代码可从https://github.com/kellyrob99/groovy-http获得 ,我希望您可以克隆一个副本以进一步了解。 简单的索引页面包含清单1中所示的“ hello world”内容。

<!DOCTYPE html>
<html>
<head>
    <title>Groovy HTTP</title>
</head>
<body>
<p>hello world</p>
</body>
</html>

清单1:用于测试的“ hello world”索引页面

我们将从使用Groovy与HTTP进行交互的最简单的可用方法开始,不提供任何其他库支持。

Groovy方法添加到String和URL

DefaultGroovyMethods类提供了几个非常方便的方法来增强String和URL类的默认操作。 特别是对于String,我们有一个新的toURL()方法,对于URL,还有一个text属性。 此外,URL类还通过使用便捷的方法来增强了与关联的InputStream和OutputStreams的配合。

String.toURL()

这是一个很小的收获,因为您真正要做的就是避免调用new URL(String spec) 。 击键的差别并不大,但是,结合Groovy的其他MetaClass优点,它对于创建流利且易于理解的代码非常有帮助。

URL.text()

对URL类的API的这种看似很小的增加使通过URLConnection流传输内容所涉及的许多通常的样板变得抽象了。 引擎盖下面是一个非常明智的实现,它缓冲了基础连接并自动为您处理所有资源的关闭。 在大多数情况下,默认行为可能就足够了,但如果不这样做,则有重载的URL.text(String charset)和URL.text(Map parameters,String charset)方法,这些方法允许修改并处理连接的更多细节组态。
清单2中的一行调用演示了如何加载html页面,并将原始html返回为String。

String html = 'http://localhost:8081/groovy-http'.toURL().text

清单2:一个衬里启动一个html页面的HTTP GET请求

对于HTTP请求使用这种简写语法,仍然有很多地方会出错,因为可能会抛出多个异常,具体取决于url的格式是否正确或指定的内容是否不存在。 清单3中显示的Spock测试同时满足了这两个条件。 请注意,404响应将导致FileNotFoundException。

@Unroll('The url #url should throw an exception of type #exception')
def 'exceptions can be thrown converting a String to URL and accessing the text'() {
    when:
    String html = url.toURL().text

    then:
    def e = thrown(exception)

    where:
    url                          | exception
    'htp://foo.com'              | MalformedURLException
    'http://google.com/notThere' | FileNotFoundException
}

清单3:Spock测试显示了我们的GET请求的一些可能的失败情况

为了进行比较,让我们看一下使用Java中的URL相同的GET请求是什么样的,如清单4所示。

URL html = new URL('http://localhost:8081/groovy-http/index.html');
URLConnection urlConnection = html.openConnection();
BufferedReader reader = new BufferedReader(
	new InputStreamReader(urlConnection.getInputStream()));
StringBuffer response = new StringBuffer();
String inputLine;
while ((inputLine = reader.readLine()) != null)
{
	response.append(inputLine)
}
reader.close();

清单4:从URLConnection读取的Java版本(基于Oracle.com的规范示例)

Java版本中仍然没有错误处理,这显然是加载相同数据的更为冗长的方法。

带有URL流的POST

与简化GET请求类似,使用Groovy执行POST可以利用常见Java类的一些增强功能。 特别地,简化的流处理允许紧密,正确和表达性的编码。 清单5显示了一个Spock测试,该测试配置了URLConnection,发布了一些数据并从连接中读取了结果。

private static final String POST_RESPONSE = 'Successfully posted [arg:[foo]] with method POST'    

def 'POST from a URLConnection'() {
    when:
    final HttpURLConnection connection = makeURL('post.groovy').toURL().openConnection()
    connection.setDoOutput(true)
    connection.outputStream.withWriter { Writer writer ->
        writer << 'arg=foo'
    }

    String response = connection.inputStream.withReader { Reader reader -> reader.text }

    then:
    connection.responseCode == HttpServletResponse.SC_OK
    response == POST_RESPONSE
}

清单5:使用Groovy和URLConnection的POST请求

请注意,我们不必显式将连接强制转换HttpUrlConnection即可获得responseCode,并且不必显式关闭任何使用的流。 同样,我们不需要像在Java中那样为Reader / Writer对象创建局部变量。 同样,不需要调用“ new”,因为对象创建全部隐藏在便捷方法的后面。 等效的Java代码需要对new进行四个调用,对close()进行两个调用,以及用于提取结果的更多相关代码。 可以在http://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html上找到有关如何使用Java进行此操作的规范示例。

注意,您还可以使用标准Groovy发行版中包含的XmlSlurper / XmlParserJsonSlurper类非常轻松地解析响应内容。

HttpClient和HTTPBuilder使事情变得更加轻松

事实是,在大多数现代Java应用程序中,开发人员有一些不错的替代方法,可以直接使用URL和URLConnection对象来使用HTTP。 可用的最受欢迎的库之一是HttpClient及其后续的HttpComponents 。 提供了所有HTTP动词的包装器,可简化响应的配置,执行和使用。 清单6显示了使用HttpClient并镜像我们先前的GET示例的Spock测试。

def 'HttpClient example in Java'() {
    when:
    HttpClient httpclient = new DefaultHttpClient();
    HttpGet httpget = new HttpGet(makeURL('helloWorld.groovy'));
    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    String responseBody = httpclient.execute(httpget, responseHandler);

    then:
    responseBody == HELLO_WORLD_HTML
}

清单6:HttpClient GET示例

如果不需要保留中间变量,则可以进一步减少。 实际上,我们可以将其简化为清单7所示的一行。

String response = new DefaultHttpClient().execute(new HttpGet(makeURL('helloWorld.groovy')), new BasicResponseHandler())

清单7:HttpClient GET单行

这显然在眼睛上容易得多,并且意图非常清晰。 HttpClient库还具有用于声明连接之间的常见行为的便捷机制,用于提供自定义响应解析实现以及对(大部分)基础资源流和连接的自动处理的API。 对于使用Groovy的我们来说,有一个很好的HttpClient包装器,称为HTTPBuilder,它添加了DSL样式的配置机制以及一些在错误处理和内容解析方面非常好的功能。 清单8再次显示了我们的标准GET示例,这次是与从新HTTPBuilder(Object uri)分配的名为http的对象一起工作。 请注意,我们使用Groovy的多重赋值功能从Closure返回并赋多个值。

def 'GET with HTTPBuilder'() {
    when:
    def (html, responseStatus) = http.get(path: 'helloWorld.groovy', contentType: TEXT) { resp, reader ->
        [reader.text, resp.status]
    }

    then:
    responseStatus == HttpServletResponse.SC_OK
    html == HELLO_WORLD_HTML
}

清单8:Spock测试显示了Groovy HTTPBuilder GET支持

如果您在清单8中注意到,我用contentType:TEXT显式设置了请求,这是因为HTTPBuilder在默认情况下提供了自动响应内容类型的检测和解析。 由于我请求的是xml文档,因此HTTPBuilder可以使用Groovy的XmlSlurper自动解析结果。 HTTPBuilder还可以检测到它是html页面,并首先通过NekoHTML传递响应,以确保您使用的是格式正确的文档。 清单9显示了我们如何与解析的响应内容进行交互的细微差别,清单8中的Closure中的阅读器被引用了解析内容的GPathResult悄然取代。

def 'GET with HTTPBuilder and automatic parsing'() {
    when:
    def (html, responseStatus) = http.get(path: 'helloWorld.groovy') { resp, reader ->
        [reader, resp.status]
    }

    then:
    responseStatus == HttpServletResponse.SC_OK
    html instanceof GPathResult
    html.BODY.P.text() == 'hello world'
}

清单9:自动检测和解析xml

您不太可能以这种方式来解析大量的html,但是由于当今有大量的xml服务可用,因此自动解析可能会非常有帮助。 JSON同样适用,如果我们给出contentType的提示,则在与此类服务进行交互时可以返回解析的JSONObject,如清单10所示。

def 'GET with HTTPBuilder and automatic JSON parsing'() {
    when:
    def (json, responseStatus) = http.get(path: 'indexJson.groovy', contentType: JSON) { resp, reader ->
        [reader, resp.status]
    }

    then:
    responseStatus == HttpServletResponse.SC_OK
    json instanceof JSONObject
    json.html.body.p == 'hello world'
}

清单10:JSON响应的自动解析

HTTPBuilder模块还具有一些处理故障情况的便捷方法。 通过为单个请求指定默认故障处理程序和特定行为,您可以使用很多选项。 清单11显示了如何定义一个简单的故障处理程序,该处理程序仅捕获响应代码。 请注意,用于获得GET响应的闭包永远不会运行,因为在这种情况下,我们请求的页面的结果为HTTP 404 Not Found响应代码。

def 'GET with HTTPBuilder and error handling'() {
    when:
    int responseStatus
    http.handler.failure = { resp ->
        responseStatus = resp.status
    }
    http.get(path: 'notThere.groovy', contentType: TEXT) { resp, reader ->
        throw new IllegalStateException('should not be executed')
    }

    then:
    responseStatus == HttpServletResponse.SC_NOT_FOUND
}

清单11:使用HTTPBuilder定义故障处理程序

使用HTTPBuilder进行数据发布也非常简单,只需要一个附加的body参数,如清单12所示。

def 'POST with HTTPBuilder'() {
    when:
    def (response, responseStatus) = http.post(path: 'post.groovy', body: [arg: 'foo']) { resp, reader ->
        [reader.text(),resp.status]
    }

    then:
    responseStatus == HttpServletResponse.SC_OK
    response == POST_RESPONSE
}

清单12:使用HTTPBuilder的POST

HTTPBuilder还提供了一些更特定的抽象来处理某些情况。 有RESTClient以简化的方式处理RESTful Web服务,有AsyncHTTPBuilder用于异步执行请求,还有Google App Engine,它不允许基于套接字的连接,还有HttpURLClient,它包装了HttpUrlConnection的用法。

结论

希望这使您对Groovy可以帮助您进行HTTP交互的工作有所了解,并为使自己的HTTP客户端应用程序变得更Groovier提供了一些想法。

更多阅读

参考:来自The Japtain on…博客的JCG合作伙伴 Kelly Robinson的Groovy和HTTP

翻译自: https://www.javacodegeeks.com/2013/02/groovy-and-http.html

groovy http

 类似资料: