我们面对的问题是行为稍有不同。我们正在使用apache cxf库进行其余的调用。对于我们来说,PATCH工作得很好,直到我们与通过HTTP工作的虚假服务进行交谈为止。与实际系统集成(通过https进行集成)的那一刻,我们开始面临以下堆栈跟踪问题。
java.net.ProtocolException: Invalid HTTP method: PATCH at java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:428) ~[na:1.7.0_51] at sun.net.www.protocol.https.HttpsURLConnectionImpl.setRequestMethod(HttpsURLConnectionImpl.java:374) ~[na:1.7.0_51] at org.apache.cxf.transport.http.URLConnectionHTTPConduit.setupConnection(URLConnectionHTTPConduit.java:149) ~[cxf-rt-transports-http-3.1.14.jar:3.1.14]
这行代码中发生了问题
connection.setRequestMethod(httpRequestMethod); in URLConnectionHTTPConduit class of cxf library
现在失败的真正原因是
java.net.HttpURLConnection contains a methods variable which looks like below
private static final String[] methods = {
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
};
我们可以看到没有定义PATCH方法,因此该错误是合理的。我们尝试了很多不同的事情,并查看了堆栈溢出。唯一合理的答案是使用反射修改方法变量以注入另一个值“ PATCH”。但是由于某种原因,我们不敢说服它使用该解决方案,因为该解决方案有点hack,而且工作量太大,并且可能会产生影响,因为我们拥有使用公共库进行所有连接并执行这些REST调用的库。
但是随后我们意识到cxf库本身正在处理异常,并且在catch块中编写了代码以使用反射添加缺少的方法。
try {
connection.setRequestMethod(httpRequestMethod);
} catch (java.net.ProtocolException ex) {
Object o = message.getContextualProperty(HTTPURL_CONNECTION_METHOD_REFLECTION);
boolean b = DEFAULT_USE_REFLECTION;
if (o != null) {
b = MessageUtils.isTrue(o);
}
if (b) {
try {
java.lang.reflect.Field f = ReflectionUtil.getDeclaredField(HttpURLConnection.class, "method");
if (connection instanceof HttpsURLConnection) {
try {
java.lang.reflect.Field f2 = ReflectionUtil.getDeclaredField(connection.getClass(),
"delegate");
Object c = ReflectionUtil.setAccessible(f2).get(connection);
if (c instanceof HttpURLConnection) {
ReflectionUtil.setAccessible(f).set(c, httpRequestMethod);
}
f2 = ReflectionUtil.getDeclaredField(c.getClass(), "httpsURLConnection");
HttpsURLConnection c2 = (HttpsURLConnection)ReflectionUtil.setAccessible(f2)
.get(c);
ReflectionUtil.setAccessible(f).set(c2, httpRequestMethod);
} catch (Throwable t) {
logStackTrace(t);
}
}
ReflectionUtil.setAccessible(f).set(connection, httpRequestMethod);
message.put(HTTPURL_CONNECTION_METHOD_REFLECTION, true);
} catch (Throwable t) {
logStackTrace(t);
throw ex;
}
}
现在这给了我们一些希望,所以我们花了一些时间阅读代码,发现如果我们提供URLConnectionHTTPConduit.HTTPURL_CONNECTION_METHOD_REFLECTION的属性,那么我们可以使cxf执行异常处理程序,并且默认情况下,变量将为由于以下代码而分配给false
DEFAULT_USE_REFLECTION =
Boolean.valueOf(SystemPropertyAction.getProperty(HTTPURL_CONNECTION_METHOD_REFLECTION, "false"));
所以这是我们要做的工作
WebClient.getConfig(client).getRequestContext().put("use.httpurlconnection.method.reflection", true);
要么
WebClient.getConfig(client).getRequestContext().put(HTTPURL_CONNECTION_METHOD_REFLECTION, true);
WebClient来自cxf库本身。
希望这个答案对您有所帮助。