如何为Java创建REST客户端?

262

通过JSR 311及其实现,我们拥有了一个强大的标准,可以通过REST公开Java对象。然而,在客户端方面,似乎缺少类似于SOAP的Apache Axis的东西 - 一些隐藏Web服务并将数据透明地编组回Java对象的东西。

您如何创建Java RESTful客户端?使用HTTPConnection和手动解析结果吗?还是使用专门的客户端,例如Jersey或Apache CXF?


2
请查看以下内容: http://igorpolevoy.blogspot.com/2011/01/java-rest-with-ease.html 谢谢 Igor - ipolevoy
请查看Resting。它承诺在一步中调用REST服务并从XML/JSON/YAML响应创建对象列表。 - neel
休息在处理POST请求时存在问题。 - RyanBrady
2
你可以用resteasy(由Jboss提供)以非常简单的方式完成它。如果您需要入门指南,我写了一篇关于如何开发Java REST客户端的博客文章。无论如何,在Java中有数百种替代方案。 - Guido
如果您对从WADL生成Java客户端类的Eclipse插件感兴趣,可以查看以下链接:https://dev59.com/Jmox5IYBdhLWcg3whUgV#16709008 - pasquy73
显示剩余3条评论
18个回答

238

这是一个老问题(2008),因此现在比那时有更多的选择:

更新(2020年仍然活跃的项目):

  • OkHttp - 基本替代JDK的HTTP组件,被许多其他候选项使用。支持更新的HTTP协议(SPDY和HTTP2)。可用于Android。不幸的是,它没有提供真正的基于反应器循环的异步选项(请参见上面的Ning和HTTP组件)。但是,如果使用较新的HTTP2协议,则这个问题就不那么严重了(假设连接数是问题)。
  • Ning Async-http-client - 提供NIO支持。以前被称为Sonatype的Async-http-client
  • Feign - 低级HTTP客户端(okhttp、apache httpcomponents)的包装器。根据接口存根自动创建客户端,类似于一些Jersey和CXF扩展。强大的Spring集成。
  • Retrofit - 低级HTTP客户端(okhttp)的包装器。根据接口存根自动创建客户端,类似于一些Jersey和CXF扩展。
  • Volley - 由Google提供的JDK HTTP客户端包装器。
  • google-http - 由Google提供的JDK HTTP客户端或Apache httpcomponents包装器。
  • Unirest - 由Kong提供的JDK HTTP客户端包装器。
  • Resteasy:JakartaEE包装JDK HTTP客户端的工具,由JBoss开发,是JBoss框架的一部分。
  • jcabi-http:Apache httpcomponents 的封装,是 jcabi 集合的一部分。
  • restlet:Apache httpcomponents 的封装,是 restlet 框架的一部分。
  • rest-assured:带有断言功能的封装,便于进行测试。
  • 在选择 HTTP/REST 客户端时,请注意检查您的框架堆栈正在使用哪个HTTP客户端以及它如何处理线程,如果可能,请使用相同的客户端。例如,如果您正在使用 Vert.x 或 Play 等框架,则可能要尝试使用其后端客户端来参与框架提供的任何总线或反应堆循环...否则,请准备好可能遇到有趣的线程问题。


    1
    以及Jersey客户端存在一些严重的内存泄漏问题 https://java.net/jira/browse/JERSEY-2830 - Dejell
    3
    Unirest非常易于使用,但它的静态设计使其在共享和服务器环境中无法使用。 - bekce
    9
    关于 unirest 的评论,我想补充说,目前(2016 年底)看起来这个项目已经不再维护了。甚至有一个 问题 提出了寻找新的维护者。 - wegenmic
    4
    对于那些喜欢Unirest的人,我有一个分支,目前正在积极维护/更新。 - Josh
    3
    希望将答案转化为社区维基,这样会更好。 - tkruse
    显示剩余9条评论

    78
    作为我在这个线程中提到的,我倾向于使用实现JAX-RS并带有很好的REST客户端的Jersey。好处在于,如果您使用JAX-RS实现RESTful资源,则Jersey客户端可以重用实体提供程序,例如JAXB / XML / JSON / Atom等 - 因此,您可以在服务器端上重用与客户端相同的对象单元测试。

    例如,这里是一个单元测试用例,来自Apache Camel项目,它从RESTful资源中查找XML有效载荷(使用JAXB对象Endpoints)。 resource(uri)方法在这个基类中定义,它只是使用Jersey客户端API。

    例如:

    clientConfig = new DefaultClientConfig();
    client = Client.create(clientConfig);
    
    resource = client.resource("http://localhost:8080");
    // let's get the XML as a String
    String text = resource("foo").accept("application/xml").get(String.class);        
    

    顺便说一下,我希望未来的JAX-RS版本能够添加一个类似Jersey中客户端API的好用的客户端API。


    有没有一种方法可以在ClientResource中指定REST服务服务器列表, 以防服务器宕机尝试下一个服务器? - Njax3SmmM2x2a0Zf7Hpd
    1
    仅仅是更新一下,但是针对詹姆斯的“顺便一提”评论,JAX-RS 2.0 的新版本将会拥有客户端 API:http://www.infoq.com/presentations/Java-REST - Nick Klauer

    69

    您可以使用标准的Java SE API:

    private void updateCustomer(Customer customer) { 
        try { 
            URL url = new URL("http://www.example.com/customers"); 
            HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
            connection.setDoOutput(true); 
            connection.setInstanceFollowRedirects(false); 
            connection.setRequestMethod("PUT"); 
            connection.setRequestProperty("Content-Type", "application/xml"); 
    
            OutputStream os = connection.getOutputStream(); 
            jaxbContext.createMarshaller().marshal(customer, os); 
            os.flush(); 
    
            connection.getResponseCode(); 
            connection.disconnect(); 
        } catch(Exception e) { 
            throw new RuntimeException(e); 
        } 
    } 
    

    或者你可以使用JAX-RS实现(如Jersey)提供的REST客户端API。这些API易于使用,但需要在类路径中添加附加的JAR包。

    WebResource resource = client.resource("http://www.example.com/customers"); 
    ClientResponse response = resource.type("application/xml");).put(ClientResponse.class, "<customer>...</customer."); 
    System.out.println(response); 
    

    更多信息请参见:


    27
    2018年时,为了进行一个简单的REST调用需要13行代码,听起来太繁琐了。 - Clint Eastwood
    3
    如果你添加错误处理和选项,它并没有太大的区别。如果SE方法看起来很长,你总是可以将其封装在一个类中... :> 经过两天的JAX-RS库冲突调试后,我真的愿意加上5行额外的代码来避免整个SPI噩梦。 - tekHedd
    4
    @ClintEastwood,这篇帖子是在2010年写的。 - 0ddlyoko

    17

    如果你只想调用REST服务并解析响应,可以尝试使用 Rest Assured

    // Make a GET request to "/lotto"
    String json = get("/lotto").asString()
    // Parse the JSON response
    List<String> winnderIds = with(json).get("lotto.winners.winnerId");
    
    // Make a POST request to "/shopping"
    String xml = post("/shopping").andReturn().body().asString()
    // Parse the XML
    Node category = with(xml).get("shopping.category[0]");
    

    1
    我发现这比许多其他提出的解决方案更优雅。 - Herve Mutombo

    10

    您还可以查看 Restlet,它具有完整的客户端能力,更加面向 REST,比底层库(如 HttpURLConnection 或 Apache HTTP Client)更为适用(我们可以将其作为连接器)。

    敬礼, Jerome Louvel


    3
    截至2019-10-24,提供的链接显示:“Restlet平台已经到达生命周期末期。” - Hans Deragon

    7

    7
    你可以尝试使用Rapa。请告诉我们您对此的反馈,并且随时记录问题或期望的功能。 Rapa。请注意保留HTML标记。

    1
    Rapa拥有非常漂亮的界面和少量依赖项。在.NET世界中,是RestSharp的一个很好的替代品。 - afternoon
    项目看起来已经停滞不前了。 - tkruse

    7

    1
    Restfulie看起来已经死了。 - tkruse

    6

    OkHttp是一个轻量而强大的HTTP客户端库,与Retrofit结合使用效果更佳。 它不仅适用于一般的Java使用,也适用于Android。

    OkHttp: http://square.github.io/okhttp/

    public static final MediaType JSON
        = MediaType.parse("application/json; charset=utf-8");
    
    OkHttpClient client = new OkHttpClient();
    
    String post(String url, String json) throws IOException {
      RequestBody body = RequestBody.create(JSON, json);
      Request request = new Request.Builder()
          .url(url)
          .post(body)
          .build();
      Response response = client.newCall(request).execute();
      return response.body().string();
    }
    

    Retrofit: http://square.github.io/retrofit/

    public interface GitHubService {
      @GET("/users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    

    6

    我最近尝试了来自Square的Retrofit库,它非常棒,你可以轻松调用你的REST API。 基于注释的配置允许我们摆脱大量样板代码。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接