우리는 약간 다른 행동으로 같은 문제에 직면했습니다. 나머지 호출을 위해 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"를 주입하도록 메소드 변수를 수정하는 것입니다. 그러나 어떻게 든 우리는 솔루션이 일종의 해킹이고 너무 많은 작업이며 모든 연결을 만들고 이러한 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를 만들어 예외 처리기를 실행할 수 있으며 기본적으로 변수가 다음과 같이 수행됩니다. 아래 코드로 인해 거짓으로 할당 됨
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 라이브러리 자체에서 가져온 것입니다.
이 답변이 도움이되기를 바랍니다.