5

我正在尝试使用 JAX-RS 的 CXF 实现在我的客户端中使用 PATCH 方法。起初我将 PATCH 注释定义为

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
}

参考这里写的: How to have a @PATCH annotation for JAX-RS?

然后我发现@PATCH 被添加到 CXF 3.1.2 中,所以我在我的 maven 的 pom.xml 中更改了版本,确实有public @interface PATCH里面,package org.apache.cxf.jaxrs.ext;代码实际上看起来和我上面发布的完全一样。

但是,当我尝试在我的服务定义上使用此注释时

@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface AbcService {

    @PATCH
    @Path("/abc/efg")
    public SomeDTO patchSomething(RequestObject request);
}

我最终得到了java.net.ProtocolException: Invalid HTTP method: PATCH我在上面发布的问题链接中所说的。他们与 Jersey 讨论了一些解决方案,但是我可以在 CXF 中做什么,以便我可以使用:

AbcService abcService = JAXRSClientFactory.create(myURI, AbcService.class, myProviders, true);
abcService.patchSomething(new RequestObject('something'));

所以我有几个问题:

  1. 我怎样才能使这项工作?不,我需要编写自定义 CXF 拦截器吗?
  2. 如果它不起作用,他们为什么要将 PATCH 注释添加到 CXF 中?
  3. 另一个主题中的一些人说,上面提到的 PATCH 注释定义对他们有用。怎么会 ?它是否只会在客户端造成麻烦,如果是这样,为什么会这样?
  4. 为什么我在 CXF 文档中找不到这个注释?我在http://cxf.apache.org/javadoc/latest/查看了 org.apache.cxf.jaxrs.ext 包,但没有看到任何补丁。然而在最新的 cxf 3.1.2 中,我真的可以在这个包中找到它。
4

2 回答 2

8

事实证明这是因为在 JAVA7 中,HttpURLConnection 不支持 PATCH,该类中支持的方法被静态定义为

   private static final String[] methods = {
        "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
    };

但是可以在 CXF 中发送 PATCH 请求,但是 Conduit 对象必须是AsyncHTTPConduit. 要使 CXF 使用 AsyncHTTPConduit,您可以像这样以编程方式实现它

AbcService service = JAXRSClientFactory.create(myURI, AbcService.class, myProviders, true);
WebClient.getConfig(service).getRequestContext().put("use.async.http.conduit", true);
service.patchEnvironmentParameters(patchRequest);

或者

WebClient client = WebClient.create("http://localhost:53261/v1-0/api/environment/parameters");
WebClient.getConfig(client).getRequestContext().put("use.async.http.conduit", true);
client.invoke("PATCH", "{}");

但要小心!!为了完成这项工作,您已将此依赖项放入您的项目中

<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http-hc</artifactId>
  <version>${cxf.version}</version>
</dependency>

还要确保使用相同版本的cxf-rt-transports-http-hccxf

但是正如你所看到的,我所描述的并没有解决原来的问题,这样我就提出了 1 个特定的 PATCH 请求。然而,在我的项目中,有许多 PATCH 服务使用我最初展示的接口定义

public interface AbcService {

    @PATCH
    @Path("/abc/efg")
    public SomeDTO patchSomething(RequestObject request);
}

因此,为了仅在 PATCH 方法上使用 AsyncHTTPConduit,我必须编写自定义 CXF 拦截器,您可以在此处了解更多信息http://cxf.apache.org/docs/interceptors.html 我编写的拦截器在 PRE_LOGIC 阶段运行它检查使用了哪种方法,如果是 PATCH,它定义了管道属性。然后在服务调用的后期阶段,CXF 使用这个属性来选择应该使用哪个 Conduit 实现,等等之后

if ( message.get(Message.HTTP_REQUEST_METHOD).equals("PATCH") {
  message.put("use.async.http.conduit", true);
}

AsyncHTTPConduit实例将与 PATCH 一起使用。

于 2015-08-21T12:47:19.413 回答
0

您能否尝试在代码中替换使用@PATCHwith@POST以查看它是否有效?您的AbcService界面错过了@Path类型级别的注释(除非它是子资源?),因此可能值得先尝试使用标准 HTTP 动词以确保正确配置其他所有内容。

于 2015-08-18T09:32:03.723 回答