【问题标题】:How do you create a REST client for Java? [closed]如何为 Java 创建 REST 客户端? [关闭]
【发布时间】:2008-10-21 10:50:58
【问题描述】:

借助 JSR 311 及其实现,我们拥有了通过 REST 公开 Java 对象的强大标准。然而,在客户端,似乎缺少与 Apache Axis for SOAP 相当的东西——隐藏 Web 服务并将数据透明地编组回 Java 对象的东西。

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

【问题讨论】:

标签: java rest client


【解决方案1】:

这是一个老问题(2008 年),所以现在有比当时更多的选择:

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

  • Apache HTTP Components (4.2) Fluent adapter - JDK 的基本替代品,已被此列表中的其他几个候选者使用。比旧的 Commons HTTP Client 3 更好,并且更易于用于构建您自己的 REST 客户端。您必须使用类似 Jackson for JSON parsing 的支持,并且可以使用类似于 Jersey/JAX-RS Rest 客户端的 HTTP components URIBuilder to construct resource URIs。 HTTP 组件也支持 NIO,但考虑到 REST 的短请求性质,我怀疑你会获得比 BIO 更好的性能。 Apache HttpComponents 5 支持 HTTP/2。
  • OkHttp - JDK 的基本替代品,类似于 http 组件,被此列表中的其他几个候选者使用。支持较新的 HTTP 协议(​​SPDY 和 HTTP2)。适用于安卓系统。不幸的是,它没有提供真正的基于反应器循环的异步选项(参见上面的 Ning 和 HTTP 组件)。但是,如果您使用较新的 HTTP2 协议,则问题不大(假设连接数有问题)。
  • Ning Async-http-client - 提供 NIO 支持。以前被 Sonatype 称为 Async-http-client
  • Feign 用于低级 http 客户端(okhttp、apache httpcomponents)的包装器。基于类似于某些 Jersey 和 CXF 扩展的接口存根自动创建客户端。强大的弹簧集成。
  • Retrofit - 低级 http 客户端 (okhttp) 的包装器。基于类似于某些 Jersey 和 CXF 扩展的接口存根自动创建客户端。
  • Volley 用于 jdk http 客户端的包装器,由 google 提供
  • google-http google 的 jdk http 客户端或 apache httpcomponents 的包装器
  • Unirest jdk http 客户端的包装器,由 kong 提供
  • Resteasy 用于 jdk http 客户端的 JakartaEE 包装器,由 jboss 提供,是 jboss 框架的一部分
  • jcabi-http apache httpcomponents 的包装器,jcabi 集合的一部分
  • restlet apache httpcomponents 的包装器,restlet 框架的一部分
  • rest-assured 带有断言的包装器,便于测试

关于选择 HTTP/REST 客户端的注意事项。确保检查您的框架堆栈为 HTTP 客户端使用了什么,它是如何处理线程的,如果提供了一个客户端,最好使用相同的客户端。也就是说,如果您使用 Vert.x 或 Play 之类的东西,您可能想尝试使用其支持客户端来参与框架提供的任何总线或反应器循环......否则请为可能有趣的线程问题做好准备。

【讨论】:

  • 不幸的是,如果使用 JDK ,Jersey 客户端不支持 PATCH 方法
  • Unirest 非常易于使用,但其静态设计使其无法在共享和服务器环境中使用。
  • 关于 unirest 评论,我想补充一点,它目前(2016 年底)看起来好像不再维护这个项目。甚至还有一个 issue 开放请求新的维护者。
  • 对于那些喜欢Unirest 的人,我有一个fork 它目前正在积极维护/更新中。
  • 将答案变成社区维基会很好
【解决方案2】:

正如我在this thread 中提到的,我倾向于使用Jersey,它实现了 JAX-RS 并带有一个不错的 REST 客户端。好消息是,如果您使用 JAX-RS 实现 RESTful 资源,那么 Jersey 客户端可以重用实体提供程序,例如 JAXB/XML/JSON/Atom 等 - 因此您可以在服务器端重用与您相同的对象在客户端单元测试中使用。

例如,Apache Camel project 中的 here is a unit test case 从 RESTful 资源中查找 XML 有效负载(使用 JAXB 对象端点)。 resource(uri) 方法在 this base class 中定义,它只使用 Jersey 客户端 API。

例如

    clientConfig = new DefaultClientConfig();
    client = Client.create(clientConfig);

    resource = client.resource("http://localhost:8080");
    // lets get the XML as a String
    String text = resource("foo").accept("application/xml").get(String.class);        

顺便说一句,我希望 JAX-RS 的未来版本能够像 Jersey 那样添加一个不错的客户端 API

【讨论】:

  • 有没有方法可以在ClientResource中提到REST服务服务器列表,以防服务器宕机尝试下一个服务器?
  • 只是一个更新,但为了解决 James 的“BTW”评论,新版本的 JAX-RS 2.0 将有一个客户端 API:infoq.com/presentations/Java-REST
【解决方案3】:

您可以使用标准的 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); 

欲了解更多信息,请参阅:

【讨论】:

  • 13 行简单的休息电话,在 2018 年,听起来太多了...
  • 添加错误处理和选项后,并没有太大的不同。如果 SE 方法看起来很长,你总是可以将它包装在一个类中...... :> 经过两天的 JAX-RS 库冲突调试后,我真的可以用 5 行额外的代码来避免整个 SPI 噩梦。跨度>
  • @ClintEastwood 这篇文章写于 2010 年
【解决方案4】:

如果您只想调用 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]");

【讨论】:

  • 我发现这比许多其他提议的解决方案更优雅。
【解决方案5】:

您还可以查看Restlet,它具有完整的客户端功能,比 HttpURLConnection 或 Apache HTTP 客户端(我们可以将其用作连接器)等低级库更面向 REST。

最好的问候, 杰罗姆·卢维尔

【讨论】:

  • 截至 2019 年 10 月 24 日,提供的链接返回:“Restlet 平台已达到使用寿命。”
【解决方案6】:

你可以试试Rapa。让我们知道您对此的反馈。 并随时记录问题或预期功能。

【讨论】:

  • Rapa 有一个非常好的界面和很少的依赖项。 .NET 世界中 RestSharp 的一个很好的替代品。
  • 项目看起来死了
【解决方案7】:

我想指出另外 2 个选项:

【讨论】:

  • Restfulie 看起来死了
【解决方案8】:

jcabi-http 尝试JdkRequest(我是一名开发人员)。它是这样工作的:

String body = new JdkRequest("http://www.google.com")
  .header("User-Agent", "it's me")
  .fetch()
  .body()

查看这篇博文了解更多详情:http://www.yegor256.com/2014/04/11/jcabi-http-intro.html

【讨论】:

    【解决方案9】:

    我最近尝试了来自 square 的 Retrofit Library,它很棒,您可以非常轻松地调用您的 REST API。 基于注解的配置可以让我们摆脱大量的样板代码。

    【讨论】:

      【解决方案10】:

      与 Retrofit 结合使用时,OkHttp 也很轻巧且功能强大。这适用于一般 Java 和 Android。

      OkHttphttp://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();
      }
      

      改造http://square.github.io/retrofit/

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

      【讨论】:

        【解决方案11】:

        我使用 Apache HTTPClient 来处理所有 HTTP 方面的事情。

        我为将 XML 解析为对象模型的 XML 内容编写 XML SAX 解析器。我相信 Axis2 还公开了 XML -> Model 方法(Axis 1 隐藏了这部分,烦人)。 XML 生成器非常简单。

        在我看来,编码不需要很长时间,而且效率很高。

        【讨论】:

        • 在我看来这是最糟糕的 REST 方式。当您有如此多的选项(如 JAXB 和 Jackson)时,在 Java 中手动处理序列化是浪费时间。即使加载整个文档并使用 XPath 也比 SAX 慢一点,与获取 XML(网络速度)相比也没什么。
        • 我也同意,我写了原始评论。那时我渴望控制反序列化,但现在我会使用 Jackson 和体面注释的模型类。
        【解决方案12】:

        由于没有人提及,这里还有一个:Feign,被Spring Cloud使用。

        【讨论】:

          【解决方案13】:

          虽然创建 HTTP 客户端并进行请求很简单。但是如果你想使用一些自动生成的客户端,你可以使用 WADL 来描述和生成代码。

          您可以使用RestDescribe 来生成和编译WSDL,您可以使用它在php、ruby、python、java 和C# 中生成客户端。它生成干净的代码,并且有一个很好的更改,您必须在代码生成后对其进行一些调整,您可以找到该工具 here 背后的良好文档和基本思想。

          wintermute 上提到的有趣和有用的WADL tools 很少。

          【讨论】:

            【解决方案14】:

            我编写了一个将 java 接口映射到远程 JSON REST 服务的库:

            https://github.com/ggeorgovassilis/spring-rest-invoker

            public interface BookService {
               @RequestMapping("/volumes")
               QueryResult findBooksByTitle(@RequestParam("q") String q);
            
               @RequestMapping("/volumes/{id}")
               Item findBookById(@PathVariable("id") String id);
            }
            

            【讨论】:

              【解决方案15】:

              jersey Rest 客户端示例:
              添加依赖:

                       <!-- jersey -->
                  <dependency>
                      <groupId>com.sun.jersey</groupId>
                      <artifactId>jersey-json</artifactId>
                      <version>1.8</version>
                  </dependency>
                 <dependency>
                      <groupId>com.sun.jersey</groupId>
                      <artifactId>jersey-server</artifactId>
                      <version>1.8</version>
                  </dependency>
              
              <dependency>
                  <groupId>com.sun.jersey</groupId>
                  <artifactId>jersey-client</artifactId>
                  <version>1.8</version>
              </dependency>
              
                  <dependency>
                  <groupId>org.json</groupId>
                  <artifactId>json</artifactId>
                  <version>20090211</version>
              </dependency>
              

              ForGetMethod 并传递两个参数:

                        Client client = Client.create();
                         WebResource webResource1 = client
                                      .resource("http://localhost:10102/NewsTickerServices/AddGroup/"
                                              + userN + "/" + groupName);
              
                              ClientResponse response1 = webResource1.get(ClientResponse.class);
                              System.out.println("responser is" + response1);
              

              GetMethod 传递一个参数并获取 List 的响应:

                     Client client = Client.create();
              
                      WebResource webResource1 = client
                                  .resource("http://localhost:10102/NewsTickerServices/GetAssignedUser/"+grpName);    
                  //value changed
                  String response1 = webResource1.type(MediaType.APPLICATION_JSON).get(String.class);
              
                  List <String > Assignedlist =new ArrayList<String>();
                   JSONArray jsonArr2 =new JSONArray(response1);
                  for (int i =0;i<jsonArr2.length();i++){
              
                      Assignedlist.add(jsonArr2.getString(i));    
                  }
              

              In Above It 返回一个 List ,我们将其作为 List 接受,然后将其转换为 Json Array ,然后将 Json Array 转换为 List 。

              如果 Post Request 传递 Json 对象作为参数:

                 Client client = Client.create();
                  WebResource webResource = client
                          .resource("http://localhost:10102/NewsTickerServices/CreateJUser");
                  // value added
              
                  ClientResponse response = webResource.type(MediaType.APPLICATION_JSON).post(ClientResponse.class,mapper.writeValueAsString(user));
              
                  if (response.getStatus() == 500) {
              
                      context.addMessage(null, new FacesMessage("User already exist "));
                  }
              

              【讨论】:

                【解决方案16】:

                我大部分时间都使用RestAssured 来解析休息服务响应并测试服务。除了 Rest Assured,我还使用以下库与 Resful 服务进行通信。

                一个。 Jersey Rest Client

                b. Spring RestTemplate

                c。 Apache HTTP Client

                【讨论】:

                  【解决方案17】:

                  尝试查看 http-rest-client

                  https://github.com/g00dnatur3/http-rest-client

                  这是一个简单的例子:

                  RestClient client = RestClient.builder().build();
                  String geocoderUrl = "http://maps.googleapis.com/maps/api/geocode/json"
                  Map<String, String> params = Maps.newHashMap();
                  params.put("address", "beverly hills 90210");
                  params.put("sensor", "false");
                  JsonNode node = client.get(geocoderUrl, params, JsonNode.class);
                  

                  该库会为您处理 json 序列化和绑定。

                  这是另一个例子,

                  RestClient client = RestClient.builder().build();
                  String url = ...
                  Person person = ...
                  Header header = client.create(url, person);
                  if (header != null) System.out.println("Location header is:" + header.value());
                  

                  最后一个例子,

                  RestClient client = RestClient.builder().build();
                  String url = ...
                  Person person = client.get(url, null, Person.class); //no queryParams
                  

                  干杯!

                  【讨论】:

                    【解决方案18】:

                    我目前正在使用https://github.com/kevinsawicki/http-request 我喜欢它们的简单性和显示示例的方式,但大多数情况下我在阅读时都被卖掉了:

                    依赖关系是什么?

                    没有。这个库的目标是成为一个带有一些内部静态类的单一类。测试项目确实需要 Jetty 来针对实际的 HTTP 服务器实现测试请求。

                    解决了一个 java 1.6 项目的一些问题。至于把json解码成对象gson简直无敌了:)

                    【讨论】:

                    • 项目看起来已经死了,自 2015 年以来没有提交。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-01-17
                    • 1970-01-01
                    • 2011-06-25
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多