我正在尝试在我的客户端中使用PATCH方法,使用JAX-RS的CXF实现。 起初我将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
,正如我在上面发布的queston链接中所说的那样。他们用Jersey讨论了一些解决方案,但是我可以在CXF中做什么,以便我可以使用:
AbcService abcService = JAXRSClientFactory.create(myURI, AbcService.class, myProviders, true);
abcService.patchSomething(new RequestObject('something'));
所以我有几个问题:
答案 0 :(得分:6)
事实证明这是因为在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-hc
和cxf
。
但是你可以看到我所描述的并没有解决原始问题,这样我只做了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,它定义了conduit属性。然后在服务调用的后期阶段,CXF使用此属性来选择应该使用哪个Conduit实现,等等
之后if ( message.get(Message.HTTP_REQUEST_METHOD).equals("PATCH") {
message.put("use.async.http.conduit", true);
}
将使用AsyncHTTPConduit
实例与PATCH一起工作。
答案 1 :(得分:0)
您是否可以尝试在代码中将@PATCH
替换为@POST
,以确定其是否有效?您的AbcService
接口错过了类型级别的@Path
注释(除非它是子资源?),因此首先尝试使用标准HTTP谓词来确保其他所有内容都已正确配置。< / p>