【问题标题】:Java's HttpURLConnection doesn't support REPORT/PROPFIND - what shall I do?Java 的 HttpURLConnection 不支持 REPORT/PROPFIND - 我该怎么办?
【发布时间】:2011-03-28 10:34:15
【问题描述】:

HttpURLConnection 仅支持 GET、POST 和 HEAD - 但不支持 REPORT/PROPFIND。我要实现一个 CalDAV 客户端,但没有这些操作(如果我想使用它们,我会得到一个 ProtocolException)我必须编写/交付一个完整的、巨大的 HTTP 库和 auth 等等。

“矫枉过正”。

如何使用 PROPFIND 和 REPORT 发送请求?

【问题讨论】:

    标签: java caldav


    【解决方案1】:

    我在 WebDav 上遇到了 PROPFIND 方法的类似问题。

    通过实施此解决方案解决了问题: https://java.net/jira/browse/JERSEY-639

        try {
                httpURLConnection.setRequestMethod(method);
            } catch (final ProtocolException pe) {
                try {
                    final Class<?> httpURLConnectionClass = httpURLConnection
                            .getClass();
                    final Class<?> parentClass = httpURLConnectionClass
                            .getSuperclass();
                    final Field methodField;
                    // If the implementation class is an HTTPS URL Connection, we
                    // need to go up one level higher in the heirarchy to modify the
                    // 'method' field.
                    if (parentClass == HttpsURLConnection.class) {
                        methodField = parentClass.getSuperclass().getDeclaredField(
                                "method");
                    } else {
                        methodField = parentClass.getDeclaredField("method");
                    }
                    methodField.setAccessible(true);
                    methodField.set(httpURLConnection, method);
                } catch (final Exception e) {
                    throw new RuntimeException(e);
    
                }
         }
    

    【讨论】:

    • 好答案!但是,在我的情况下, httpURLConnection 有一个委托并且答案不起作用。因此,我通过反射提取了 httpURLConnection 对象的委托字段。 delegate 字段也是 HttpURLConnection 的(sub sub)子类。我通过 methodField = parentClass.getSuperclass().getSuperclass().getDeclaredField("method"); 将您的程序应用于此委托连接。这很好用。谢谢!
    • 我尝试了上述解决方案,并得到错误为“不允许使用http方法”。您能否就此提供任何指示。我还看到 httpURLConnection 有一个委托,但是当我尝试注释解决方案时,我得到 noSuchMethod 错误。
    • @KNaito 你能帮我解决这个问题吗,我正在使用 JDK 1.7 并直接使用 HttpUrlConnection
    • 我使用以下代码,``` if (parentClass == HttpsURLConnection.class) { methodField = parentClass.getSuperclass().getDeclaredField("method"); } else if (parentClass == HttpURLConnection.class) { methodField = parentClass.getDeclaredField("method"); } else { methodField = parentClass.getSuperclass().getSuperclass().getDeclaredField("method"); } methodField.setAccessible(true); methodField.set(httpURLConnection, 方法); ``` @Dhamayanthi
    • 另外一个就是if语句中的HttpsURLConnection/HttpsURLConnection是javax.net.ssl.Https.URLConnection/java.net.HttpURLConnection。注意 java.net.HttpURLConnection 类有一个受保护的method 字段。
    【解决方案2】:

    您可能希望为此查找 WebDAV 库,而不是 HTTP 库。

    也许看看Apache Jackrabbit

    【讨论】:

    【解决方案3】:

    你可以使用https://github.com/square/okhttp

    示例代码

        // using OkHttp
        public class PropFindExample {        
        private final OkHttpClient client = new OkHttpClient();
        String run(String url) throws IOException {
            String credential = Credentials.basic(userName, password);
            // body
            String body = "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\">\n" +
                    "  <d:prop>\n" +
                    "     <d:displayname />\n" +
                    "     <d:getetag />\n" +
                    "  </d:prop>\n" +
                    "</d:propfind>";
            Request request = new Request.Builder()
                    .url(url)
                    .method("PROPFIND", RequestBody.create(MediaType.parse(body), body))
                    .header("DEPTH", "1")
                    .header("Authorization", credential)
                    .header("Content-Type", "text/xml")
                    .build();
    
            Response response = client.newCall(request).execute();
            return response.body().string();
        }
     }
    

    或者玩 Sockets

    示例代码

    String host = "example.com";
    int port = 443;
    String path = "/placeholder";
    String userName = "username";
    String password = "password";
    
    SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
    Socket socket = ssf.createSocket(host, port);
    PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
    
    // xml data to be sent in body
    String xmlData = "<?xml version=\"1.0\"?> <d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\"> <d:prop> <d:displayname /> <d:getetag /> </d:prop> </d:propfind>";
    // append headers
    out.println("PROPFIND path HTTP/1.1");
    out.println("Host: "+host);
    String userCredentials = username+":"+password;
    String basicAuth = "Basic " + new String(Base64.encode(userCredentials.getBytes(), Base64.DEFAULT));
    String authorization = "Authorization: " + basicAuth;
    out.println(authorization.trim());
    out.println("Content-Length: "+ xmlData.length());
    out.println("Content-Type: text/xml");
    out.println("Depth: 1");
    out.println();
    // append body
    out.println(xmlData);
    out.flush();
    
    // get response
    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String inputLine;
    
    System.out.println("--------------------------------------------------------");
    System.out.println("---------------Printing response--------------------------");
    System.out.println("--------------------------------------------------------");
    while ((inputLine = in.readLine()) != null) {
        System.out.println(inputLine);
    }
    
    in.close();
    

    【讨论】:

    • 请不要copy/paste多个问题的答案相同。而是自定义各个问题的答案,并解释他们如何解决该特定问题。
    • 当然!感谢您的留言!
    【解决方案4】:

    您可以尝试使用另一个 HTTP 库,例如 Apache HTTP client 并扩展其 HttpRequestBase(例如,参见 HttpGetHttpPost)。

    或者,您可以直接使用 WebDAV 客户端库。

    【讨论】:

      【解决方案5】:

      考虑使用Caldav4j

      它支持:

      • 轻松生成报告请求
      • 基于httpclient 3.0
      • 安卓应用
      • 目前正在迁移到jackrabbit

      【讨论】:

        【解决方案6】:
        private static void setRequestMethod(HttpURLConnection conn, String method) throws Throwable {
            try {
                conn.setRequestMethod(method);
            } catch (ProtocolException e) {
                Class<?> c = conn.getClass();
                Field methodField = null;
                Field delegateField = null;
                try {
                    delegateField = c.getDeclaredField("delegate");
                } catch (NoSuchFieldException nsfe) {
        
                }
                while (c != null && methodField == null) {
                    try {
                        methodField = c.getDeclaredField("method");
                    } catch (NoSuchFieldException nsfe) {
        
                    }
                    if (methodField == null) {
                        c = c.getSuperclass();
                    }
                }
                if (methodField != null) {
                    methodField.setAccessible(true);
                    methodField.set(conn, method);
                }
        
                if (delegateField != null) {
                    delegateField.setAccessible(true);
                    HttpURLConnection delegate = (HttpURLConnection) delegateField.get(conn);
                    setRequestMethod(delegate, method);
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          "方法PROPFIND不能有请求体。执行此代码时发生此异常。"

          【讨论】:

          • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
          【解决方案8】:

          "方法PROPFIND不能有请求体。执行上面示例代码3的代码时会发生此异常。

          【讨论】:

          • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
          猜你喜欢
          • 2016-01-20
          • 1970-01-01
          • 2017-12-23
          • 1970-01-01
          • 1970-01-01
          • 2016-11-11
          • 1970-01-01
          • 2011-04-25
          • 2023-02-22
          相关资源
          最近更新 更多