【问题标题】:How to send enclose data in DELETE request in Jersey client?如何在 Jersey 客户端的 DELETE 请求中发送附件数据?
【发布时间】:2014-10-03 11:46:36
【问题描述】:

我在 Jersey 2.x 中有以下服务器端代码:

@Path("/store/remove/from/group")
@DELETE
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public Response removeStoresFromGroup(@FormParam("storeName") List<String> storeNames, @FormParam("groupName") String groupName) {
    //......
}

在客户端,我想使用 Jersey 2.x 客户端向上述 Web 服务发送删除请求。但是,从Jersey client API的文档中,我没有找到如何在DELETE请求中包含以下数据:

WebTarget webTarget = client.target("/store/remove/from/group");
MultivaluedMap<String, String> formData = new MultivaluedHashMap<String, String>();
List<String> storeName = new ArrayList<String>();
storeName.add("Store1");
storeName.add("Store2");
storeName.add("Store3");

formData.addAll("storeName", storeName);
formData.add("groupName", "Group A");

Response response = webTarget.request().accept(MediaType.TEXT_PLAIN).delete();   //The delete() method doesn't take any entity body in the request.

从 Jersey 客户端 API 来看,SyncInvoker 类不支持将实体主体作为参数的 delete 方法。所以我只能使用 POST 或 PUT 将数据发送到服务器,如下所示(但不能用于 DELETE):

Response response = webTarget.request().accept(MediaType.TEXT_PLAIN).post(Entity.form(formData)); 

但我想使用 DELETE 请求,因为该请求正在删除一些资源。如何通过 Jersey 客户端发送带有某些实体数据的 DELETE 请求?

【问题讨论】:

  • OT 但通常您不需要发送带有 DELETE because 的实体“DELETE 方法请求源服务器删除由 Request-URI 标识的资源”。您的方法引用听起来更像是更新引用然后删除资源。
  • 有时候如果我想删除一些满足一定条件的数据,我需要在DELETE请求的实体体中传入一些参数。

标签: java rest jersey jax-rs


【解决方案1】:

我也使用过 RESTeasy Jersey 客户端并为我工作:

响应响应 = client.target(yourUrlToCall).request(MediaType.APPLICATION_JSON) .build("DELETE", Entity.entity(yourJsonDTO, MediaType.APPLICATION_JSON)).invoke();

对于解决一些正常使用get()、delete()等不“允许”的复杂场景非常有用。

【讨论】:

    【解决方案2】:

    请注意:如果你使用JAX RS Client APIresteasy实现,你可以使用build().invoke()

    client.target("$baseUrl$restEndPoint/$entityId")
                    .request("application/json")
                    .build("DELETE", Entity.entity(entity, MediaType.APPLICATION_JSON))
                    .invoke()
    

    但它不适用于jersey

    【讨论】:

    • JerseyInvocation 中有 validateHttpMethodAndEntity 函数来验证方法和实体的存在。这将抛出 IllegalStateException
    • @pshirishreddy,我使用 JAX RS 客户端 API 的 resteasy 实现。它有效。
    • 同意,但 OP 问题与球衣客户有关 :)
    • resteasy 是球衣客户
    【解决方案3】:

    基于 Jersey 2.18 版本的代码,JerseyInvocation 类使用预定义的 HashMap 来验证 HTTP 方法及其实体如下:

    map.put("DELETE", EntityPresence.MUST_BE_NULL);
    map.put("GET", EntityPresence.MUST_BE_NULL);
    ...
    

    这就是为什么我们得到这个错误“Entity must be null for http method DELETE”。

    同时请注意,它还提供了一个 Jersey 客户端配置属性ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION 来决定是否停止其余的执行,所以这里我们可以使用这个属性来抑制验证,以便继续发送一个DELETE向实体请求。例如

        ClientConfig config = new ClientConfig();
        config.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
        Client client = ClientBuilder.newClient(config);
        ...
    

    【讨论】:

    • 我也有类似的需要这样做,虽然在我的情况下我实际上没有要发送的正文,但我确实需要强制发送“内容长度:0”删除。用 Jersey Client 2.5.2 尝试这个建议,我得到一个 ProtocolException: java.net.ProtocolException: HTTP method DELETE does not support output at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1081)在 org.glassfish.jersey.client.HttpUrlConnector$3.getOutputStream(HttpUrlConnector.java:267)
    • 我尝试覆盖 org.glassfish.jersey.test.JerseyTest#configureClient 并将 ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION 设置为 true 已失败。不再有例外,而是我得到了 400 的服务响应。
    • 我正在将一个服务器应用程序从 Play Framework 转换为纯 JavaEE,并且有一个采用 JSON 正文的 DELETE 资源。我不能只破坏旧的 API,所以这对我有帮助!
    【解决方案4】:

    带有实体主体 is not strictly forbiddenDELETE 但它非常罕见,并且被某些框架/服务器忽略。实体主体的需要可能表明 DELETE 未按预期使用。

    例如:如果GET /customers/4711 返回一位客户,而您发送DELETE /customers/4711,则此资源上的下一个GET 应返回404。您删除了一个由 URL 标识的资源,例如 defined in the spec

    您的 URL /store/remove/from/group 似乎无法识别资源。使用 /store/4711/groups/4711 之类的标识符并在其上发送 DELETE 不符合您的需求,因为您希望“从组中删除商店”而不是删除商店或组。

    假设你有一个组资源

    {
      "id" : 4711,
      "stores" : [123, 456, 789]
    }
    

    你想要这样的结果

    {
      "id" : 4711,
      "stores" : [123, 789]
    }
    

    您没有删除任何内容。您正在修改资源,因此 PUTPOSTPATCH 是合适的方法。 JSON-Patch 是描述此类更改的好格式。请求如下所示:

    PATCH /groups/4711 HTTP/1.1
    Content-Type: application/json-patch
    
    [
      {
        "op" : "remove"
        "path" : "stores/1"
      }
    ]
    

    【讨论】:

    • 感谢您的建议。 Jersey 框架目前似乎不支持 PATCH 方法。像 Tomcat 或 Jetty 这样的 Java Web 服务器是否也支持 HTTP PATCH 方法?在这种情况下我可以使用 PUT 请求,因为我正在修改资源。
    • 对不起,我不知道哪个容器或框架支持PATCHPUT 是个好主意,但这有你需要 send the whole modified resource 的缺点。
    • 谢谢。为了稳定起见,我暂时只使用 http PUT ,希望 http PATCH 方法将在以后的 Jersey 版本中正式包含。
    【解决方案5】:

    您可以使用webTarget.request().accept(MediaType.TEXT_PLAIN).method("DELETE",yourEntity) 调用带有实体的DELETE

    【讨论】:

    • 我使用这个方法时报错:“Entity must be null for http method DELETE”。这是为什么呢?
    • 嗯,我真的没想到会这样。如果您查看第 9.6 节中的 [1],您会发现 DELETE 是基于 URI 的。虽然它并没有说它不能使用身体.. [1]:w3.org/Protocols/rfc2616/rfc2616-sec9.html
    • 我不明白为什么删除请求不能包含文档中的实体主体。但是 javadoc (docs.oracle.com/javaee/7/api/javax/ws/rs/client/…) 并没有说它不能使用 DELETE 作为方法名。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 2021-06-23
    • 2014-10-24
    相关资源
    最近更新 更多