我们遇到了同样的问题,但行为略有不同。我们使用 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
/* valid HTTP methods */
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) {
//ignore
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 库本身。
希望这个答案对某人有所帮助。