HTTPBuilder:使用Groovy操作HTTP资源

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

如果熟悉HttpClient,那么你对HTTPBuilder就不会感到陌生,它是对前者的封装,使之更符合Groovy的使用惯例。下面的例子摘自HTTPBuilder的文档,它充分展示了自己的特点:

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。
    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'

希望通过本文的浮光掠影式的介绍,能让大家对于HTTPBuilder有个简单的了解;)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


背景:    8月29日,凌晨4点左右,某服务告警,其中一个节点直接down掉,收到告警的同事让运维重启。    9点左右,内存监控上发现内存异常,堆内存涨速很快,即便GC也没有什么效果,频繁GC。    9点38,服务各种超时,影响整个app使用。处理方式:    当时由于很想要
https://support.smartbear.comeadyapi/docs/soapui/steps/groovy.htmlGettestcaseobjectToobtaintheobjectwhichreferstothecontainingtestcase,usethefollowingcodesnippet:Groovy def case=testRunner.testCase; Byusingthe tes
有几个选项可用于执行自定义JMeter脚本并扩展基线JMeter功能。查看最流行的扩展机制,比较性能并分析哪一个是最好的。  这是乐队之战,JMeter风格。 BeanshellV.JSR223V.JavaRequestSampler 在我们之前的帖子中,  JMeterPerformance和TuningTips  ( 由fantastik
Scala和Java为静态语言,Groovy为动态语言Scala:函数式编程,同时支持面向对象Groovy:jvm上的脚本,较好兼容java语法,Groovy加强了Java集成。 可配置化的优势,可以将一些简单的逻辑公开给外部编辑和使用,增强了互操作性,复杂逻辑来说,可配置化代码的调试则会比较麻烦 Scala和Java
出处:https://www.jianshu.com/p/ce6f8a1f66f4一、一些内部元件的访问testRunner.testCase开头1、向下访问testRunner.testCase.testSteps[testStepName]testRunner.testCase.getTestStepByName("新增一个空间")2、向上访问,用于访问同一项目中的其他testSuites和testCase下
在运行groovy的junit方法时,报了这个错误:java.lang.ExceptionInInitializerError atorg.codehaus.groovy.reflection.ClassInfo.isValidWeakMetaClass(ClassInfo.java:271) atorg.codehaus.groovy.reflection.ClassInfo.getMetaClassForClass(ClassInfo.java:241) atorg.codeha
基本语法1.Grovvy的注释分为//和/**/和java的一样.2.Grovvy语法可以不已分号结尾.3.单引号,里面的内容严格的对应java中的String,不对$符号进行转义.defs1='iamastudent$'printlns1iamastudent$4.双引号“”的内容中如果有$号的话,会先对表达式先求值.de
Tiobe发布了最新一期(3月份)编程语言欢迎度榜单,其榜单根据互联网上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube统计出排名数据。TOP5几乎没有变化,Java和C语言牢牢占据前两名。Python相较去年上升一位进入TOP3,C++下
我有一个Google地图组件,作者可以在其中指定纬度和经度.我正在使用带有正则表达式的常规“输入”类型控件来验证它们是否是数字,但是,当试图解决指定范围的问题时(经度验证该值在[-180,180]内并且纬度[-90,90])但是,通过正则表达式进行验证似乎很麻烦,而且利用inputtype=“numb
我正在为未来的应用程序评估SpringBoot,并希望使用Groovy模板来实现其纯粹的可读性.不幸的是,我在迭代我添加到控制器返回的ModelAndView对象的对象列表时遇到了麻烦.这是我的控制器:@RestController@RequestMapping("/ships")publicclassShipsController{@Autowired
我有一个基于Spring的java应用程序,其中包含一些有用的组件.作为系统的一部分,我有一个groovy脚本,来处理一些报告.我想从groovy脚本中调用spring组件.当我用Java编写时,我需要在@Component中使用@Autowired注释,即@ComponentclassReporter{@AutowiredSearchServicesearchS
在Grailsi18n插件definedthusly中定义了一个messageSourcebean:messageSource(PluginAwareResourceBundleMessageSource){basenames=baseNames.toArray()fallbackToSystemLocale=falsepluginManager=manager....}是否可以覆盖我的resources.groovy中的fa
我正在寻找一种方法来反向工程RDBMS表(MSSQLServer)并生成JPA@EntityGroovy类.我们目前没有选择使用Grails和/或GORM,因此Grailsdb-reverse-engineer插件似乎很接近但不太正确.它生成符合GORM的类而不是JPA实体类.我们目前有一个gradle构建,它利用org.hibernate.tool.ant.Hibe
https://blog.csdn.net/Gdeer/article/details/83062523一、直接运行groovy程序因为groovy插件和android插件不兼容,所以不能在原始项目上使用groovy。 新建module,创一个JavaLibrary,取名lib。  修改lib/build.gradleapplyplugin:'java-library'depe
一、自动生成GET请求脚本1、配置Createascript在ngrinder管理台主页,点击script–>Createascript,并填写脚本名称和请求的url,如下所示:点击Create按钮,nGrinder会自动生成对应的脚本结构,如果没有参数需要设置的话,可以直接运行了。二、详细解析GET请求脚本ngrinder自动生成的脚本
我正在关注使用列表和地图作为构造函数的this博文.为什么以下列表无法强制反对?classTest{staticclassTestObject{privateinta=1;protectedintb=2;publicintc=3;intd=4;Strings="s";}stati
Information:java:Errorsoccurredwhilecompilingmodule'security'Information:javac1.8.0_131wasusedtocompilejavasourcesInformation:2019/6/98:31-Buildcompletedwith1errorand0warningsin3s116msError:java:读取E:\repository\org
ngrinder中的groovy脚本结构类似junit,同时在junit的基础之上封装了自己的注解,用来控制脚本的运行。一、运行逻辑图如下:此处只列出了groovy脚本的逻辑,jython脚本是类似的,在此不再单独介绍。二、各注解的使用比较三、关注点在ngrinder中,通常使用单进程多线程就足够大部分测试了,所以:
我有一个switch语句来处理javaenumfoo,并使用spock编写一些groovy单元测试.我已经添加了一个测试,它验证当前是否处理了每种类型的foo而没有抛出异常.现在我想测试一个无法识别的foo类型会导致抛出异常.要做到这一点,我将不得不嘲笑枚举,并已经看到这里概述的解决方案:MockingJ
我有一个groovy实体ClientInvoiceAttachmentExt,它扩展了java实体ClientInvoiceAttachment.ClientInvoiceAttachment具有@Id注释,但仍然看到“没有为实体指定的标识符”错误这是我的堆栈跟踪[Mar0317:11:54]ERROR|org.springframework.web.context.ContextLoader|Contex