(转)HTTPBuilder:使用Groovy操作HTTP资源

如今的Web,孤立的应用已经不再吃香,随之而来的是与其他应用(如Twitter)或服务(如S3)交互的意愿越来越强烈。对于Groovy而言,HTTPBuilder绝对是应对这一需求的不二之选。

如果熟悉HttpClient,那么你对HTTPBuilder就不会感到陌生,它是对前者的封装,使之更符合Groovy的使用惯例。下面的例子摘自HTTPBuilder的文档,它充分展示了自己的特点:
[/code]
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.TEXT

def http = new HTTPBuilder( 'http://www.google.com/search' )

http.request(GET,TEXT) { req ->
uri.path = '/mail/help/tasks/'
headers.'User-Agent' = 'Mozilla/5.0'

//请求成功
response.success = { resp, reader ->
assert resp.statusLine.statusCode == 200
println "My response handler got response: ${resp.statusLine}"
println "Response length: ${resp.headers.'Content-Length'}"
System.out << reader // print response stream
}

//404
response.'404' = { resp ->
println 'Not found'
}

// 401
http.handler.'401' = { resp ->
println "Access denied"
}

//其他错误,不实现则采用缺省的:抛出异常。
http.handler.failure = { resp ->
println "Unexpected failure: ${resp.statusLine}"
}
}

无需过多的讲解,上述的例子已经非常明白地说明了HTTPBuilder的基本使用。尽管如此,对于上例中的内容类型(即request括号中的TEXT),还是有必要啰嗦几句。HTTPBuilder支持对响应内容的自动解析,解析的方式可在请求中指定,缺省除了TEXT之外,还支持XML、HTML和JSON。如果在请求中不指定解析方式,那么它会根据响应的内容类型选择最合适的方式进行解析。对于每一种内容类型:

TEXT,纯文本
XML,采用XmlSlurper解析内容
HTML,先采用NekoHTML使HTML规范化,之后采用XmlSlurper解析DOM
JSON,采用JSON-lib解析内容
要想按照自己的意愿解析内容,你可以创建自己的内容解析器:

import au.com.bytecode.opencsv.CSVReader
import groovyx.net.http.ParserRegistry

//注册自己的内容类型和解析器
http.parser.'text/csv' = { resp ->
return new CSVReader( new InputStreamReader( resp.entity.content
, ParserRegistry.getCharset( resp ) ) )
}

//验证使用
http.get( uri : 'http://somehost.com/contacts.csv'
, contentType : 'text/csv' ) { resp, csv ->
assert csv instanceof CSVReader
// parse the csv stream here.
}

除了展示如何支持新的内容类型,上例还展示另一种GET请求方法:直接使用HTTPBuilder的get方法。该方法简化了GET请求的操作,非常适合简单的场景。提到了GET,就不能不提POST,使用HTTPBuilder完成POST请求的方法如下:

import groovyx.net.http.HTTPBuilder

def http = new HTTPBuilder('http://twitter.com/statuses/')

http.request( POST ) {
uri.path = 'update.xml'
body = [ status : 'update!' , source : 'httpbuilder' ]
requestContentType = ContentType.URLENC

response.success = { resp ->
println "Tweet response status: ${resp.statusLine}"
assert resp.statusLine.statusCode == 200
}
}

同样非常简单,不同则在于POST中需要指定body和requestContentType,使用它完全可以模拟窗体的提交。在GET请求中我们谈到了对于响应内容的解析,与之对应的则是如何在POST中提交不同的内容类型:

XML:使用StreamingMarkupBuilder。
[/code]
http.request( POST, XML ) {
body = {
auth {
user 'Bob'
password 'pass'
}
}
}

JSON:借助Json-Lib的JsonGroovyBuilder动态构造。

http.request( POST, JSON ) { req ->
body = [
first : 'Bob',
last : 'Builder',
address : [
street : '123 Some St',
town : 'Boston',
state : 'MA',
zip : 12345
]
]

response.success = { resp, json ->...}
}

同样,HTTPBuilder对于POST也提供了便利的post方法,关于它的使用也请参见文档。

REST是如今Web的宠儿,许多Web 2.0 API都宣称自己是RESTful的。且不论其中的真伪,作为给HTTP操作提供DSL的工具,HTTPBuilder自然没有错过这个潮流。RESTClient便是它对于这种趋势的回应,其本身是HTTPBuilder的子类,虽然损失了部分灵活性,但简化了为GET、PUT、POST、DELETE和HEAD操作:

twitter = new RESTClient( 'https://twitter.com/statuses/' )

//HEAD
twitter.head( path : 'public_timeline.json' ).status == 200

//GET
def resp = twitter.get( path : 'friends_timeline.json' )

//POST
def msg = "I'm using HTTPBuilder's RESTClient on ${new Date()}"
resp = twitter.post( path : 'update.xml',
body : [ status:msg, source:'httpbuilder' ]
, requestContentType : URLENC )

//DELETE
resp = twitter.delete( path : "destroy/${postID}.json" )

AsyncHTTPBuilder是该工具的另一个类,看名字就知道,它主要用于异步请求。它的使用方式类似HTTPBuilder,只是返回结果是一个java.util.concurrent.Future类型,关于它的使用详情,可参见文档。

想找台免费的机器吗?现在已完全不是天方夜谭,Google GAE就是你要找的目标。虽然说它是免费的并不完全对,它在一定配额内免费,但这个配额对于个人实验或小规模的应用,应该够用了。开发GAE应用对于Grails来讲并非难事,但如果你想在应用里使用HTTPBuilder去发起请求,那么就不会那么顺利。由于GAE的安全限制,你不能直接去打开Socket,这正是HTTPBuilder底层(HttpClient)的机制。这时,就需要使用HTTPURLConnection完成这一任务。以它为基础,HTTPBuilder工具包内提供了另一个兼容GAE的“HTTPBuilder”:HttpURLClient。使用其他并不复杂:

import groovyx.net.http.*

def http = new HttpURLClient( url: 'http://twitter.com/statuses/' )
def resp = http.request( path: 'user_timeline.json'
, query: [id:'httpbuilder', count:5] )
println "JSON response: ${resp.status}"
resp.data.each {
println it.created_at
println ' ' + it.text
}

本文最后要介绍的一个组件是URIBuilder,它并不直接面对HTTP请求,而是辅助HTTPBuilder构造复杂的URL,在其内部使用。它的基本使用如下:

import groovyx.net.http.URIBuilder

def uri = new URIBuilder( 'http://www.google.com/one/two?a=1#frag' )

uri.scheme = 'https'
assert uri.toString() == 'https://www.google.com:80/one/two?a=1#frag'

uri.host = 'localhost'
assert uri.toString() == 'https://localhost:80/one/two?a=1#frag'

uri.port = 8080
assert uri.toString() == 'https://localhost:8080/one/two?a=1#frag'

uri.fragment = 'asdf2'
assert uri.toString() == 'https://localhost:8080/one/two?a=1#asdf2'

// relative paths:
uri.path = 'three/four.html'
assert uri.toString() == 'https://localhost:8080/one/three/four.html?a=1#asdf2'
uri.path = '../four/five'
assert uri.toString() == 'https://localhost:8080/one/four/five?a=1#asdf2'

// control the entire path with leading '/' :
uri.path = '/six'
assert uri.toString() == 'https://localhost:8080/six?a=1#asdf2'

同时也提供了对查询字符串的处理:

def uri = new groovyx.net.http.URIBuilder( 'http://localhost?a=1&b=2' )

assert uri.query instanceof Map
assert uri.query.a == '1'
assert uri.query.b == '2'

uri.addQueryParam 'd', '4'
uri.removeQueryParam 'b'

assert uri.toString() == 'http://localhost?d=4&a=1'

uri.query = [z:0,y:9,x:8]
assert uri.toString() == 'http://localhost?z=0&y=9&x=8'

uri.query = null
assert uri.toString() == 'http://localhost'

// parameters are also properly escaped as well:
uri.query = [q:'a:b',z:'war & peace']
assert uri.toString() == 'http://localhost?q=a%3Ab&z=war+%26+peace'



参考:[url]http://my.oschina.net/groovyland/blog/3035[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值